##// END OF EJS Templates
revset: lookup descendents for negative arguments to ancestor operator...
David Soria Parra -
r32699:f75d0aa5 default
parent child Browse files
Show More
@@ -1,222 +1,223
1 Mercurial supports several ways to specify revisions.
1 Mercurial supports several ways to specify revisions.
2
2
3 Specifying single revisions
3 Specifying single revisions
4 ===========================
4 ===========================
5
5
6 A plain integer is treated as a revision number. Negative integers are
6 A plain integer is treated as a revision number. Negative integers are
7 treated as sequential offsets from the tip, with -1 denoting the tip,
7 treated as sequential offsets from the tip, with -1 denoting the tip,
8 -2 denoting the revision prior to the tip, and so forth.
8 -2 denoting the revision prior to the tip, and so forth.
9
9
10 A 40-digit hexadecimal string is treated as a unique revision identifier.
10 A 40-digit hexadecimal string is treated as a unique revision identifier.
11 A hexadecimal string less than 40 characters long is treated as a
11 A hexadecimal string less than 40 characters long is treated as a
12 unique revision identifier and is referred to as a short-form
12 unique revision identifier and is referred to as a short-form
13 identifier. A short-form identifier is only valid if it is the prefix
13 identifier. A short-form identifier is only valid if it is the prefix
14 of exactly one full-length identifier.
14 of exactly one full-length identifier.
15
15
16 Any other string is treated as a bookmark, tag, or branch name. A
16 Any other string is treated as a bookmark, tag, or branch name. A
17 bookmark is a movable pointer to a revision. A tag is a permanent name
17 bookmark is a movable pointer to a revision. A tag is a permanent name
18 associated with a revision. A branch name denotes the tipmost open branch head
18 associated with a revision. A branch name denotes the tipmost open branch head
19 of that branch - or if they are all closed, the tipmost closed head of the
19 of that branch - or if they are all closed, the tipmost closed head of the
20 branch. Bookmark, tag, and branch names must not contain the ":" character.
20 branch. Bookmark, tag, and branch names must not contain the ":" character.
21
21
22 The reserved name "tip" always identifies the most recent revision.
22 The reserved name "tip" always identifies the most recent revision.
23
23
24 The reserved name "null" indicates the null revision. This is the
24 The reserved name "null" indicates the null revision. This is the
25 revision of an empty repository, and the parent of revision 0.
25 revision of an empty repository, and the parent of revision 0.
26
26
27 The reserved name "." indicates the working directory parent. If no
27 The reserved name "." indicates the working directory parent. If no
28 working directory is checked out, it is equivalent to null. If an
28 working directory is checked out, it is equivalent to null. If an
29 uncommitted merge is in progress, "." is the revision of the first
29 uncommitted merge is in progress, "." is the revision of the first
30 parent.
30 parent.
31
31
32 Finally, commands that expect a single revision (like ``hg update``) also
32 Finally, commands that expect a single revision (like ``hg update``) also
33 accept revsets (see below for details). When given a revset, they use the
33 accept revsets (see below for details). When given a revset, they use the
34 last revision of the revset. A few commands accept two single revisions
34 last revision of the revset. A few commands accept two single revisions
35 (like ``hg diff``). When given a revset, they use the first and the last
35 (like ``hg diff``). When given a revset, they use the first and the last
36 revisions of the revset.
36 revisions of the revset.
37
37
38 Specifying multiple revisions
38 Specifying multiple revisions
39 =============================
39 =============================
40
40
41 Mercurial supports a functional language for selecting a set of
41 Mercurial supports a functional language for selecting a set of
42 revisions. Expressions in this language are called revsets.
42 revisions. Expressions in this language are called revsets.
43
43
44 The language supports a number of predicates which are joined by infix
44 The language supports a number of predicates which are joined by infix
45 operators. Parenthesis can be used for grouping.
45 operators. Parenthesis can be used for grouping.
46
46
47 Identifiers such as branch names may need quoting with single or
47 Identifiers such as branch names may need quoting with single or
48 double quotes if they contain characters like ``-`` or if they match
48 double quotes if they contain characters like ``-`` or if they match
49 one of the predefined predicates.
49 one of the predefined predicates.
50
50
51 Special characters can be used in quoted identifiers by escaping them,
51 Special characters can be used in quoted identifiers by escaping them,
52 e.g., ``\n`` is interpreted as a newline. To prevent them from being
52 e.g., ``\n`` is interpreted as a newline. To prevent them from being
53 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
53 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
54
54
55 Operators
55 Operators
56 =========
56 =========
57
57
58 There is a single prefix operator:
58 There is a single prefix operator:
59
59
60 ``not x``
60 ``not x``
61 Changesets not in x. Short form is ``! x``.
61 Changesets not in x. Short form is ``! x``.
62
62
63 These are the supported infix operators:
63 These are the supported infix operators:
64
64
65 ``x::y``
65 ``x::y``
66 A DAG range, meaning all changesets that are descendants of x and
66 A DAG range, meaning all changesets that are descendants of x and
67 ancestors of y, including x and y themselves. If the first endpoint
67 ancestors of y, including x and y themselves. If the first endpoint
68 is left out, this is equivalent to ``ancestors(y)``, if the second
68 is left out, this is equivalent to ``ancestors(y)``, if the second
69 is left out it is equivalent to ``descendants(x)``.
69 is left out it is equivalent to ``descendants(x)``.
70
70
71 An alternative syntax is ``x..y``.
71 An alternative syntax is ``x..y``.
72
72
73 ``x:y``
73 ``x:y``
74 All changesets with revision numbers between x and y, both
74 All changesets with revision numbers between x and y, both
75 inclusive. Either endpoint can be left out, they default to 0 and
75 inclusive. Either endpoint can be left out, they default to 0 and
76 tip.
76 tip.
77
77
78 ``x and y``
78 ``x and y``
79 The intersection of changesets in x and y. Short form is ``x & y``.
79 The intersection of changesets in x and y. Short form is ``x & y``.
80
80
81 ``x or y``
81 ``x or y``
82 The union of changesets in x and y. There are two alternative short
82 The union of changesets in x and y. There are two alternative short
83 forms: ``x | y`` and ``x + y``.
83 forms: ``x | y`` and ``x + y``.
84
84
85 ``x - y``
85 ``x - y``
86 Changesets in x but not in y.
86 Changesets in x but not in y.
87
87
88 ``x % y``
88 ``x % y``
89 Changesets that are ancestors of x but not ancestors of y (i.e. ::x - ::y).
89 Changesets that are ancestors of x but not ancestors of y (i.e. ::x - ::y).
90 This is shorthand notation for ``only(x, y)`` (see below). The second
90 This is shorthand notation for ``only(x, y)`` (see below). The second
91 argument is optional and, if left out, is equivalent to ``only(x)``.
91 argument is optional and, if left out, is equivalent to ``only(x)``.
92
92
93 ``x^n``
93 ``x^n``
94 The nth parent of x, n == 0, 1, or 2.
94 The nth parent of x, n == 0, 1, or 2.
95 For n == 0, x; for n == 1, the first parent of each changeset in x;
95 For n == 0, x; for n == 1, the first parent of each changeset in x;
96 for n == 2, the second parent of changeset in x.
96 for n == 2, the second parent of changeset in x.
97
97
98 ``x~n``
98 ``x~n``
99 The nth first ancestor of x; ``x~0`` is x; ``x~3`` is ``x^^^``.
99 The nth first ancestor of x; ``x~0`` is x; ``x~3`` is ``x^^^``.
100 For n < 0, the nth unambiguous descendent of x.
100
101
101 ``x ## y``
102 ``x ## y``
102 Concatenate strings and identifiers into one string.
103 Concatenate strings and identifiers into one string.
103
104
104 All other prefix, infix and postfix operators have lower priority than
105 All other prefix, infix and postfix operators have lower priority than
105 ``##``. For example, ``a1 ## a2~2`` is equivalent to ``(a1 ## a2)~2``.
106 ``##``. For example, ``a1 ## a2~2`` is equivalent to ``(a1 ## a2)~2``.
106
107
107 For example::
108 For example::
108
109
109 [revsetalias]
110 [revsetalias]
110 issue(a1) = grep(r'\bissue[ :]?' ## a1 ## r'\b|\bbug\(' ## a1 ## r'\)')
111 issue(a1) = grep(r'\bissue[ :]?' ## a1 ## r'\b|\bbug\(' ## a1 ## r'\)')
111
112
112 ``issue(1234)`` is equivalent to
113 ``issue(1234)`` is equivalent to
113 ``grep(r'\bissue[ :]?1234\b|\bbug\(1234\)')``
114 ``grep(r'\bissue[ :]?1234\b|\bbug\(1234\)')``
114 in this case. This matches against all of "issue 1234", "issue:1234",
115 in this case. This matches against all of "issue 1234", "issue:1234",
115 "issue1234" and "bug(1234)".
116 "issue1234" and "bug(1234)".
116
117
117 There is a single postfix operator:
118 There is a single postfix operator:
118
119
119 ``x^``
120 ``x^``
120 Equivalent to ``x^1``, the first parent of each changeset in x.
121 Equivalent to ``x^1``, the first parent of each changeset in x.
121
122
122 Patterns
123 Patterns
123 ========
124 ========
124
125
125 Where noted, predicates that perform string matching can accept a pattern
126 Where noted, predicates that perform string matching can accept a pattern
126 string. The pattern may be either a literal, or a regular expression. If the
127 string. The pattern may be either a literal, or a regular expression. If the
127 pattern starts with ``re:``, the remainder of the pattern is treated as a
128 pattern starts with ``re:``, the remainder of the pattern is treated as a
128 regular expression. Otherwise, it is treated as a literal. To match a pattern
129 regular expression. Otherwise, it is treated as a literal. To match a pattern
129 that actually starts with ``re:``, use the prefix ``literal:``.
130 that actually starts with ``re:``, use the prefix ``literal:``.
130
131
131 Matching is case-sensitive, unless otherwise noted. To perform a case-
132 Matching is case-sensitive, unless otherwise noted. To perform a case-
132 insensitive match on a case-sensitive predicate, use a regular expression,
133 insensitive match on a case-sensitive predicate, use a regular expression,
133 prefixed with ``(?i)``.
134 prefixed with ``(?i)``.
134
135
135 For example, ``tag(r're:(?i)release')`` matches "release" or "RELEASE"
136 For example, ``tag(r're:(?i)release')`` matches "release" or "RELEASE"
136 or "Release", etc
137 or "Release", etc
137
138
138 Predicates
139 Predicates
139 ==========
140 ==========
140
141
141 The following predicates are supported:
142 The following predicates are supported:
142
143
143 .. predicatesmarker
144 .. predicatesmarker
144
145
145 Aliases
146 Aliases
146 =======
147 =======
147
148
148 New predicates (known as "aliases") can be defined, using any combination of
149 New predicates (known as "aliases") can be defined, using any combination of
149 existing predicates or other aliases. An alias definition looks like::
150 existing predicates or other aliases. An alias definition looks like::
150
151
151 <alias> = <definition>
152 <alias> = <definition>
152
153
153 in the ``revsetalias`` section of a Mercurial configuration file. Arguments
154 in the ``revsetalias`` section of a Mercurial configuration file. Arguments
154 of the form `a1`, `a2`, etc. are substituted from the alias into the
155 of the form `a1`, `a2`, etc. are substituted from the alias into the
155 definition.
156 definition.
156
157
157 For example,
158 For example,
158
159
159 ::
160 ::
160
161
161 [revsetalias]
162 [revsetalias]
162 h = heads()
163 h = heads()
163 d(s) = sort(s, date)
164 d(s) = sort(s, date)
164 rs(s, k) = reverse(sort(s, k))
165 rs(s, k) = reverse(sort(s, k))
165
166
166 defines three aliases, ``h``, ``d``, and ``rs``. ``rs(0:tip, author)`` is
167 defines three aliases, ``h``, ``d``, and ``rs``. ``rs(0:tip, author)`` is
167 exactly equivalent to ``reverse(sort(0:tip, author))``.
168 exactly equivalent to ``reverse(sort(0:tip, author))``.
168
169
169 Equivalents
170 Equivalents
170 ===========
171 ===========
171
172
172 Command line equivalents for :hg:`log`::
173 Command line equivalents for :hg:`log`::
173
174
174 -f -> ::.
175 -f -> ::.
175 -d x -> date(x)
176 -d x -> date(x)
176 -k x -> keyword(x)
177 -k x -> keyword(x)
177 -m -> merge()
178 -m -> merge()
178 -u x -> user(x)
179 -u x -> user(x)
179 -b x -> branch(x)
180 -b x -> branch(x)
180 -P x -> !::x
181 -P x -> !::x
181 -l x -> limit(expr, x)
182 -l x -> limit(expr, x)
182
183
183 Examples
184 Examples
184 ========
185 ========
185
186
186 Some sample queries:
187 Some sample queries:
187
188
188 - Changesets on the default branch::
189 - Changesets on the default branch::
189
190
190 hg log -r "branch(default)"
191 hg log -r "branch(default)"
191
192
192 - Changesets on the default branch since tag 1.5 (excluding merges)::
193 - Changesets on the default branch since tag 1.5 (excluding merges)::
193
194
194 hg log -r "branch(default) and 1.5:: and not merge()"
195 hg log -r "branch(default) and 1.5:: and not merge()"
195
196
196 - Open branch heads::
197 - Open branch heads::
197
198
198 hg log -r "head() and not closed()"
199 hg log -r "head() and not closed()"
199
200
200 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
201 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
201 ``hgext/*``::
202 ``hgext/*``::
202
203
203 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
204 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
204
205
205 - Changesets committed in May 2008, sorted by user::
206 - Changesets committed in May 2008, sorted by user::
206
207
207 hg log -r "sort(date('May 2008'), user)"
208 hg log -r "sort(date('May 2008'), user)"
208
209
209 - Changesets mentioning "bug" or "issue" that are not in a tagged
210 - Changesets mentioning "bug" or "issue" that are not in a tagged
210 release::
211 release::
211
212
212 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tag())"
213 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tag())"
213
214
214 - Update to commit that bookmark @ is pointing too, without activating the
215 - Update to commit that bookmark @ is pointing too, without activating the
215 bookmark (this works because the last revision of the revset is used)::
216 bookmark (this works because the last revision of the revset is used)::
216
217
217 hg update :@
218 hg update :@
218
219
219 - Show diff between tags 1.3 and 1.5 (this works because the first and the
220 - Show diff between tags 1.3 and 1.5 (this works because the first and the
220 last revisions of the revset are used)::
221 last revisions of the revset are used)::
221
222
222 hg diff -r 1.3::1.5
223 hg diff -r 1.3::1.5
@@ -1,2328 +1,2349
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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import heapq
10 import heapq
11 import re
11 import re
12
12
13 from .i18n import _
13 from .i18n import _
14 from . import (
14 from . import (
15 destutil,
15 destutil,
16 encoding,
16 encoding,
17 error,
17 error,
18 hbisect,
18 hbisect,
19 match as matchmod,
19 match as matchmod,
20 node,
20 node,
21 obsolete as obsmod,
21 obsolete as obsmod,
22 pathutil,
22 pathutil,
23 phases,
23 phases,
24 registrar,
24 registrar,
25 repoview,
25 repoview,
26 revsetlang,
26 revsetlang,
27 scmutil,
27 scmutil,
28 smartset,
28 smartset,
29 util,
29 util,
30 )
30 )
31
31
32 # helpers for processing parsed tree
32 # helpers for processing parsed tree
33 getsymbol = revsetlang.getsymbol
33 getsymbol = revsetlang.getsymbol
34 getstring = revsetlang.getstring
34 getstring = revsetlang.getstring
35 getinteger = revsetlang.getinteger
35 getinteger = revsetlang.getinteger
36 getboolean = revsetlang.getboolean
36 getboolean = revsetlang.getboolean
37 getlist = revsetlang.getlist
37 getlist = revsetlang.getlist
38 getrange = revsetlang.getrange
38 getrange = revsetlang.getrange
39 getargs = revsetlang.getargs
39 getargs = revsetlang.getargs
40 getargsdict = revsetlang.getargsdict
40 getargsdict = revsetlang.getargsdict
41
41
42 # constants used as an argument of match() and matchany()
42 # constants used as an argument of match() and matchany()
43 anyorder = revsetlang.anyorder
43 anyorder = revsetlang.anyorder
44 defineorder = revsetlang.defineorder
44 defineorder = revsetlang.defineorder
45 followorder = revsetlang.followorder
45 followorder = revsetlang.followorder
46
46
47 baseset = smartset.baseset
47 baseset = smartset.baseset
48 generatorset = smartset.generatorset
48 generatorset = smartset.generatorset
49 spanset = smartset.spanset
49 spanset = smartset.spanset
50 fullreposet = smartset.fullreposet
50 fullreposet = smartset.fullreposet
51
51
52 def _revancestors(repo, revs, followfirst):
52 def _revancestors(repo, revs, followfirst):
53 """Like revlog.ancestors(), but supports followfirst."""
53 """Like revlog.ancestors(), but supports followfirst."""
54 if followfirst:
54 if followfirst:
55 cut = 1
55 cut = 1
56 else:
56 else:
57 cut = None
57 cut = None
58 cl = repo.changelog
58 cl = repo.changelog
59
59
60 def iterate():
60 def iterate():
61 revs.sort(reverse=True)
61 revs.sort(reverse=True)
62 irevs = iter(revs)
62 irevs = iter(revs)
63 h = []
63 h = []
64
64
65 inputrev = next(irevs, None)
65 inputrev = next(irevs, None)
66 if inputrev is not None:
66 if inputrev is not None:
67 heapq.heappush(h, -inputrev)
67 heapq.heappush(h, -inputrev)
68
68
69 seen = set()
69 seen = set()
70 while h:
70 while h:
71 current = -heapq.heappop(h)
71 current = -heapq.heappop(h)
72 if current == inputrev:
72 if current == inputrev:
73 inputrev = next(irevs, None)
73 inputrev = next(irevs, None)
74 if inputrev is not None:
74 if inputrev is not None:
75 heapq.heappush(h, -inputrev)
75 heapq.heappush(h, -inputrev)
76 if current not in seen:
76 if current not in seen:
77 seen.add(current)
77 seen.add(current)
78 yield current
78 yield current
79 try:
79 try:
80 for parent in cl.parentrevs(current)[:cut]:
80 for parent in cl.parentrevs(current)[:cut]:
81 if parent != node.nullrev:
81 if parent != node.nullrev:
82 heapq.heappush(h, -parent)
82 heapq.heappush(h, -parent)
83 except error.WdirUnsupported:
83 except error.WdirUnsupported:
84 for parent in repo[current].parents()[:cut]:
84 for parent in repo[current].parents()[:cut]:
85 if parent.rev() != node.nullrev:
85 if parent.rev() != node.nullrev:
86 heapq.heappush(h, -parent.rev())
86 heapq.heappush(h, -parent.rev())
87
87
88 return generatorset(iterate(), iterasc=False)
88 return generatorset(iterate(), iterasc=False)
89
89
90 def _revdescendants(repo, revs, followfirst):
90 def _revdescendants(repo, revs, followfirst):
91 """Like revlog.descendants() but supports followfirst."""
91 """Like revlog.descendants() but supports followfirst."""
92 if followfirst:
92 if followfirst:
93 cut = 1
93 cut = 1
94 else:
94 else:
95 cut = None
95 cut = None
96
96
97 def iterate():
97 def iterate():
98 cl = repo.changelog
98 cl = repo.changelog
99 # XXX this should be 'parentset.min()' assuming 'parentset' is a
99 # XXX this should be 'parentset.min()' assuming 'parentset' is a
100 # smartset (and if it is not, it should.)
100 # smartset (and if it is not, it should.)
101 first = min(revs)
101 first = min(revs)
102 nullrev = node.nullrev
102 nullrev = node.nullrev
103 if first == nullrev:
103 if first == nullrev:
104 # Are there nodes with a null first parent and a non-null
104 # Are there nodes with a null first parent and a non-null
105 # second one? Maybe. Do we care? Probably not.
105 # second one? Maybe. Do we care? Probably not.
106 for i in cl:
106 for i in cl:
107 yield i
107 yield i
108 else:
108 else:
109 seen = set(revs)
109 seen = set(revs)
110 for i in cl.revs(first + 1):
110 for i in cl.revs(first + 1):
111 for x in cl.parentrevs(i)[:cut]:
111 for x in cl.parentrevs(i)[:cut]:
112 if x != nullrev and x in seen:
112 if x != nullrev and x in seen:
113 seen.add(i)
113 seen.add(i)
114 yield i
114 yield i
115 break
115 break
116
116
117 return generatorset(iterate(), iterasc=True)
117 return generatorset(iterate(), iterasc=True)
118
118
119 def _reachablerootspure(repo, minroot, roots, heads, includepath):
119 def _reachablerootspure(repo, minroot, roots, heads, includepath):
120 """return (heads(::<roots> and ::<heads>))
120 """return (heads(::<roots> and ::<heads>))
121
121
122 If includepath is True, return (<roots>::<heads>)."""
122 If includepath is True, return (<roots>::<heads>)."""
123 if not roots:
123 if not roots:
124 return []
124 return []
125 parentrevs = repo.changelog.parentrevs
125 parentrevs = repo.changelog.parentrevs
126 roots = set(roots)
126 roots = set(roots)
127 visit = list(heads)
127 visit = list(heads)
128 reachable = set()
128 reachable = set()
129 seen = {}
129 seen = {}
130 # prefetch all the things! (because python is slow)
130 # prefetch all the things! (because python is slow)
131 reached = reachable.add
131 reached = reachable.add
132 dovisit = visit.append
132 dovisit = visit.append
133 nextvisit = visit.pop
133 nextvisit = visit.pop
134 # open-code the post-order traversal due to the tiny size of
134 # open-code the post-order traversal due to the tiny size of
135 # sys.getrecursionlimit()
135 # sys.getrecursionlimit()
136 while visit:
136 while visit:
137 rev = nextvisit()
137 rev = nextvisit()
138 if rev in roots:
138 if rev in roots:
139 reached(rev)
139 reached(rev)
140 if not includepath:
140 if not includepath:
141 continue
141 continue
142 parents = parentrevs(rev)
142 parents = parentrevs(rev)
143 seen[rev] = parents
143 seen[rev] = parents
144 for parent in parents:
144 for parent in parents:
145 if parent >= minroot and parent not in seen:
145 if parent >= minroot and parent not in seen:
146 dovisit(parent)
146 dovisit(parent)
147 if not reachable:
147 if not reachable:
148 return baseset()
148 return baseset()
149 if not includepath:
149 if not includepath:
150 return reachable
150 return reachable
151 for rev in sorted(seen):
151 for rev in sorted(seen):
152 for parent in seen[rev]:
152 for parent in seen[rev]:
153 if parent in reachable:
153 if parent in reachable:
154 reached(rev)
154 reached(rev)
155 return reachable
155 return reachable
156
156
157 def reachableroots(repo, roots, heads, includepath=False):
157 def reachableroots(repo, roots, heads, includepath=False):
158 """return (heads(::<roots> and ::<heads>))
158 """return (heads(::<roots> and ::<heads>))
159
159
160 If includepath is True, return (<roots>::<heads>)."""
160 If includepath is True, return (<roots>::<heads>)."""
161 if not roots:
161 if not roots:
162 return baseset()
162 return baseset()
163 minroot = roots.min()
163 minroot = roots.min()
164 roots = list(roots)
164 roots = list(roots)
165 heads = list(heads)
165 heads = list(heads)
166 try:
166 try:
167 revs = repo.changelog.reachableroots(minroot, heads, roots, includepath)
167 revs = repo.changelog.reachableroots(minroot, heads, roots, includepath)
168 except AttributeError:
168 except AttributeError:
169 revs = _reachablerootspure(repo, minroot, roots, heads, includepath)
169 revs = _reachablerootspure(repo, minroot, roots, heads, includepath)
170 revs = baseset(revs)
170 revs = baseset(revs)
171 revs.sort()
171 revs.sort()
172 return revs
172 return revs
173
173
174 # helpers
174 # helpers
175
175
176 def getset(repo, subset, x):
176 def getset(repo, subset, x):
177 if not x:
177 if not x:
178 raise error.ParseError(_("missing argument"))
178 raise error.ParseError(_("missing argument"))
179 return methods[x[0]](repo, subset, *x[1:])
179 return methods[x[0]](repo, subset, *x[1:])
180
180
181 def _getrevsource(repo, r):
181 def _getrevsource(repo, r):
182 extra = repo[r].extra()
182 extra = repo[r].extra()
183 for label in ('source', 'transplant_source', 'rebase_source'):
183 for label in ('source', 'transplant_source', 'rebase_source'):
184 if label in extra:
184 if label in extra:
185 try:
185 try:
186 return repo[extra[label]].rev()
186 return repo[extra[label]].rev()
187 except error.RepoLookupError:
187 except error.RepoLookupError:
188 pass
188 pass
189 return None
189 return None
190
190
191 # operator methods
191 # operator methods
192
192
193 def stringset(repo, subset, x):
193 def stringset(repo, subset, x):
194 x = scmutil.intrev(repo[x])
194 x = scmutil.intrev(repo[x])
195 if (x in subset
195 if (x in subset
196 or x == node.nullrev and isinstance(subset, fullreposet)):
196 or x == node.nullrev and isinstance(subset, fullreposet)):
197 return baseset([x])
197 return baseset([x])
198 return baseset()
198 return baseset()
199
199
200 def rangeset(repo, subset, x, y, order):
200 def rangeset(repo, subset, x, y, order):
201 m = getset(repo, fullreposet(repo), x)
201 m = getset(repo, fullreposet(repo), x)
202 n = getset(repo, fullreposet(repo), y)
202 n = getset(repo, fullreposet(repo), y)
203
203
204 if not m or not n:
204 if not m or not n:
205 return baseset()
205 return baseset()
206 return _makerangeset(repo, subset, m.first(), n.last(), order)
206 return _makerangeset(repo, subset, m.first(), n.last(), order)
207
207
208 def rangeall(repo, subset, x, order):
208 def rangeall(repo, subset, x, order):
209 assert x is None
209 assert x is None
210 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
210 return _makerangeset(repo, subset, 0, len(repo) - 1, order)
211
211
212 def rangepre(repo, subset, y, order):
212 def rangepre(repo, subset, y, order):
213 # ':y' can't be rewritten to '0:y' since '0' may be hidden
213 # ':y' can't be rewritten to '0:y' since '0' may be hidden
214 n = getset(repo, fullreposet(repo), y)
214 n = getset(repo, fullreposet(repo), y)
215 if not n:
215 if not n:
216 return baseset()
216 return baseset()
217 return _makerangeset(repo, subset, 0, n.last(), order)
217 return _makerangeset(repo, subset, 0, n.last(), order)
218
218
219 def rangepost(repo, subset, x, order):
219 def rangepost(repo, subset, x, order):
220 m = getset(repo, fullreposet(repo), x)
220 m = getset(repo, fullreposet(repo), x)
221 if not m:
221 if not m:
222 return baseset()
222 return baseset()
223 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
223 return _makerangeset(repo, subset, m.first(), len(repo) - 1, order)
224
224
225 def _makerangeset(repo, subset, m, n, order):
225 def _makerangeset(repo, subset, m, n, order):
226 if m == n:
226 if m == n:
227 r = baseset([m])
227 r = baseset([m])
228 elif n == node.wdirrev:
228 elif n == node.wdirrev:
229 r = spanset(repo, m, len(repo)) + baseset([n])
229 r = spanset(repo, m, len(repo)) + baseset([n])
230 elif m == node.wdirrev:
230 elif m == node.wdirrev:
231 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
231 r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
232 elif m < n:
232 elif m < n:
233 r = spanset(repo, m, n + 1)
233 r = spanset(repo, m, n + 1)
234 else:
234 else:
235 r = spanset(repo, m, n - 1)
235 r = spanset(repo, m, n - 1)
236
236
237 if order == defineorder:
237 if order == defineorder:
238 return r & subset
238 return r & subset
239 else:
239 else:
240 # carrying the sorting over when possible would be more efficient
240 # carrying the sorting over when possible would be more efficient
241 return subset & r
241 return subset & r
242
242
243 def dagrange(repo, subset, x, y, order):
243 def dagrange(repo, subset, x, y, order):
244 r = fullreposet(repo)
244 r = fullreposet(repo)
245 xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
245 xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
246 includepath=True)
246 includepath=True)
247 return subset & xs
247 return subset & xs
248
248
249 def andset(repo, subset, x, y, order):
249 def andset(repo, subset, x, y, order):
250 return getset(repo, getset(repo, subset, x), y)
250 return getset(repo, getset(repo, subset, x), y)
251
251
252 def differenceset(repo, subset, x, y, order):
252 def differenceset(repo, subset, x, y, order):
253 return getset(repo, subset, x) - getset(repo, subset, y)
253 return getset(repo, subset, x) - getset(repo, subset, y)
254
254
255 def _orsetlist(repo, subset, xs):
255 def _orsetlist(repo, subset, xs):
256 assert xs
256 assert xs
257 if len(xs) == 1:
257 if len(xs) == 1:
258 return getset(repo, subset, xs[0])
258 return getset(repo, subset, xs[0])
259 p = len(xs) // 2
259 p = len(xs) // 2
260 a = _orsetlist(repo, subset, xs[:p])
260 a = _orsetlist(repo, subset, xs[:p])
261 b = _orsetlist(repo, subset, xs[p:])
261 b = _orsetlist(repo, subset, xs[p:])
262 return a + b
262 return a + b
263
263
264 def orset(repo, subset, x, order):
264 def orset(repo, subset, x, order):
265 xs = getlist(x)
265 xs = getlist(x)
266 if order == followorder:
266 if order == followorder:
267 # slow path to take the subset order
267 # slow path to take the subset order
268 return subset & _orsetlist(repo, fullreposet(repo), xs)
268 return subset & _orsetlist(repo, fullreposet(repo), xs)
269 else:
269 else:
270 return _orsetlist(repo, subset, xs)
270 return _orsetlist(repo, subset, xs)
271
271
272 def notset(repo, subset, x, order):
272 def notset(repo, subset, x, order):
273 return subset - getset(repo, subset, x)
273 return subset - getset(repo, subset, x)
274
274
275 def listset(repo, subset, *xs):
275 def listset(repo, subset, *xs):
276 raise error.ParseError(_("can't use a list in this context"),
276 raise error.ParseError(_("can't use a list in this context"),
277 hint=_('see hg help "revsets.x or y"'))
277 hint=_('see hg help "revsets.x or y"'))
278
278
279 def keyvaluepair(repo, subset, k, v):
279 def keyvaluepair(repo, subset, k, v):
280 raise error.ParseError(_("can't use a key-value pair in this context"))
280 raise error.ParseError(_("can't use a key-value pair in this context"))
281
281
282 def func(repo, subset, a, b, order):
282 def func(repo, subset, a, b, order):
283 f = getsymbol(a)
283 f = getsymbol(a)
284 if f in symbols:
284 if f in symbols:
285 func = symbols[f]
285 func = symbols[f]
286 if getattr(func, '_takeorder', False):
286 if getattr(func, '_takeorder', False):
287 return func(repo, subset, b, order)
287 return func(repo, subset, b, order)
288 return func(repo, subset, b)
288 return func(repo, subset, b)
289
289
290 keep = lambda fn: getattr(fn, '__doc__', None) is not None
290 keep = lambda fn: getattr(fn, '__doc__', None) is not None
291
291
292 syms = [s for (s, fn) in symbols.items() if keep(fn)]
292 syms = [s for (s, fn) in symbols.items() if keep(fn)]
293 raise error.UnknownIdentifier(f, syms)
293 raise error.UnknownIdentifier(f, syms)
294
294
295 # functions
295 # functions
296
296
297 # symbols are callables like:
297 # symbols are callables like:
298 # fn(repo, subset, x)
298 # fn(repo, subset, x)
299 # with:
299 # with:
300 # repo - current repository instance
300 # repo - current repository instance
301 # subset - of revisions to be examined
301 # subset - of revisions to be examined
302 # x - argument in tree form
302 # x - argument in tree form
303 symbols = {}
303 symbols = {}
304
304
305 # symbols which can't be used for a DoS attack for any given input
305 # symbols which can't be used for a DoS attack for any given input
306 # (e.g. those which accept regexes as plain strings shouldn't be included)
306 # (e.g. those which accept regexes as plain strings shouldn't be included)
307 # functions that just return a lot of changesets (like all) don't count here
307 # functions that just return a lot of changesets (like all) don't count here
308 safesymbols = set()
308 safesymbols = set()
309
309
310 predicate = registrar.revsetpredicate()
310 predicate = registrar.revsetpredicate()
311
311
312 @predicate('_destupdate')
312 @predicate('_destupdate')
313 def _destupdate(repo, subset, x):
313 def _destupdate(repo, subset, x):
314 # experimental revset for update destination
314 # experimental revset for update destination
315 args = getargsdict(x, 'limit', 'clean')
315 args = getargsdict(x, 'limit', 'clean')
316 return subset & baseset([destutil.destupdate(repo, **args)[0]])
316 return subset & baseset([destutil.destupdate(repo, **args)[0]])
317
317
318 @predicate('_destmerge')
318 @predicate('_destmerge')
319 def _destmerge(repo, subset, x):
319 def _destmerge(repo, subset, x):
320 # experimental revset for merge destination
320 # experimental revset for merge destination
321 sourceset = None
321 sourceset = None
322 if x is not None:
322 if x is not None:
323 sourceset = getset(repo, fullreposet(repo), x)
323 sourceset = getset(repo, fullreposet(repo), x)
324 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
324 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
325
325
326 @predicate('adds(pattern)', safe=True)
326 @predicate('adds(pattern)', safe=True)
327 def adds(repo, subset, x):
327 def adds(repo, subset, x):
328 """Changesets that add a file matching pattern.
328 """Changesets that add a file matching pattern.
329
329
330 The pattern without explicit kind like ``glob:`` is expected to be
330 The pattern without explicit kind like ``glob:`` is expected to be
331 relative to the current directory and match against a file or a
331 relative to the current directory and match against a file or a
332 directory.
332 directory.
333 """
333 """
334 # i18n: "adds" is a keyword
334 # i18n: "adds" is a keyword
335 pat = getstring(x, _("adds requires a pattern"))
335 pat = getstring(x, _("adds requires a pattern"))
336 return checkstatus(repo, subset, pat, 1)
336 return checkstatus(repo, subset, pat, 1)
337
337
338 @predicate('ancestor(*changeset)', safe=True)
338 @predicate('ancestor(*changeset)', safe=True)
339 def ancestor(repo, subset, x):
339 def ancestor(repo, subset, x):
340 """A greatest common ancestor of the changesets.
340 """A greatest common ancestor of the changesets.
341
341
342 Accepts 0 or more changesets.
342 Accepts 0 or more changesets.
343 Will return empty list when passed no args.
343 Will return empty list when passed no args.
344 Greatest common ancestor of a single changeset is that changeset.
344 Greatest common ancestor of a single changeset is that changeset.
345 """
345 """
346 # i18n: "ancestor" is a keyword
346 # i18n: "ancestor" is a keyword
347 l = getlist(x)
347 l = getlist(x)
348 rl = fullreposet(repo)
348 rl = fullreposet(repo)
349 anc = None
349 anc = None
350
350
351 # (getset(repo, rl, i) for i in l) generates a list of lists
351 # (getset(repo, rl, i) for i in l) generates a list of lists
352 for revs in (getset(repo, rl, i) for i in l):
352 for revs in (getset(repo, rl, i) for i in l):
353 for r in revs:
353 for r in revs:
354 if anc is None:
354 if anc is None:
355 anc = repo[r]
355 anc = repo[r]
356 else:
356 else:
357 anc = anc.ancestor(repo[r])
357 anc = anc.ancestor(repo[r])
358
358
359 if anc is not None and anc.rev() in subset:
359 if anc is not None and anc.rev() in subset:
360 return baseset([anc.rev()])
360 return baseset([anc.rev()])
361 return baseset()
361 return baseset()
362
362
363 def _ancestors(repo, subset, x, followfirst=False):
363 def _ancestors(repo, subset, x, followfirst=False):
364 heads = getset(repo, fullreposet(repo), x)
364 heads = getset(repo, fullreposet(repo), x)
365 if not heads:
365 if not heads:
366 return baseset()
366 return baseset()
367 s = _revancestors(repo, heads, followfirst)
367 s = _revancestors(repo, heads, followfirst)
368 return subset & s
368 return subset & s
369
369
370 @predicate('ancestors(set)', safe=True)
370 @predicate('ancestors(set)', safe=True)
371 def ancestors(repo, subset, x):
371 def ancestors(repo, subset, x):
372 """Changesets that are ancestors of a changeset in set.
372 """Changesets that are ancestors of a changeset in set.
373 """
373 """
374 return _ancestors(repo, subset, x)
374 return _ancestors(repo, subset, x)
375
375
376 @predicate('_firstancestors', safe=True)
376 @predicate('_firstancestors', safe=True)
377 def _firstancestors(repo, subset, x):
377 def _firstancestors(repo, subset, x):
378 # ``_firstancestors(set)``
378 # ``_firstancestors(set)``
379 # Like ``ancestors(set)`` but follows only the first parents.
379 # Like ``ancestors(set)`` but follows only the first parents.
380 return _ancestors(repo, subset, x, followfirst=True)
380 return _ancestors(repo, subset, x, followfirst=True)
381
381
382 def _childrenspec(repo, subset, x, n, order):
383 """Changesets that are the Nth child of a changeset
384 in set.
385 """
386 cs = set()
387 for r in getset(repo, fullreposet(repo), x):
388 for i in range(n):
389 c = repo[r].children()
390 if len(c) == 0:
391 break
392 if len(c) > 1:
393 raise error.RepoLookupError(
394 _("revision in set has more than one child"))
395 r = c[0]
396 else:
397 cs.add(r)
398 return subset & cs
399
382 def ancestorspec(repo, subset, x, n, order):
400 def ancestorspec(repo, subset, x, n, order):
383 """``set~n``
401 """``set~n``
384 Changesets that are the Nth ancestor (first parents only) of a changeset
402 Changesets that are the Nth ancestor (first parents only) of a changeset
385 in set.
403 in set.
386 """
404 """
387 n = getinteger(n, _("~ expects a number"))
405 n = getinteger(n, _("~ expects a number"))
406 if n < 0:
407 # children lookup
408 return _childrenspec(repo, subset, x, -n, order)
388 ps = set()
409 ps = set()
389 cl = repo.changelog
410 cl = repo.changelog
390 for r in getset(repo, fullreposet(repo), x):
411 for r in getset(repo, fullreposet(repo), x):
391 for i in range(n):
412 for i in range(n):
392 try:
413 try:
393 r = cl.parentrevs(r)[0]
414 r = cl.parentrevs(r)[0]
394 except error.WdirUnsupported:
415 except error.WdirUnsupported:
395 r = repo[r].parents()[0].rev()
416 r = repo[r].parents()[0].rev()
396 ps.add(r)
417 ps.add(r)
397 return subset & ps
418 return subset & ps
398
419
399 @predicate('author(string)', safe=True)
420 @predicate('author(string)', safe=True)
400 def author(repo, subset, x):
421 def author(repo, subset, x):
401 """Alias for ``user(string)``.
422 """Alias for ``user(string)``.
402 """
423 """
403 # i18n: "author" is a keyword
424 # i18n: "author" is a keyword
404 n = getstring(x, _("author requires a string"))
425 n = getstring(x, _("author requires a string"))
405 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
426 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
406 return subset.filter(lambda x: matcher(repo[x].user()),
427 return subset.filter(lambda x: matcher(repo[x].user()),
407 condrepr=('<user %r>', n))
428 condrepr=('<user %r>', n))
408
429
409 @predicate('bisect(string)', safe=True)
430 @predicate('bisect(string)', safe=True)
410 def bisect(repo, subset, x):
431 def bisect(repo, subset, x):
411 """Changesets marked in the specified bisect status:
432 """Changesets marked in the specified bisect status:
412
433
413 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
434 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
414 - ``goods``, ``bads`` : csets topologically good/bad
435 - ``goods``, ``bads`` : csets topologically good/bad
415 - ``range`` : csets taking part in the bisection
436 - ``range`` : csets taking part in the bisection
416 - ``pruned`` : csets that are goods, bads or skipped
437 - ``pruned`` : csets that are goods, bads or skipped
417 - ``untested`` : csets whose fate is yet unknown
438 - ``untested`` : csets whose fate is yet unknown
418 - ``ignored`` : csets ignored due to DAG topology
439 - ``ignored`` : csets ignored due to DAG topology
419 - ``current`` : the cset currently being bisected
440 - ``current`` : the cset currently being bisected
420 """
441 """
421 # i18n: "bisect" is a keyword
442 # i18n: "bisect" is a keyword
422 status = getstring(x, _("bisect requires a string")).lower()
443 status = getstring(x, _("bisect requires a string")).lower()
423 state = set(hbisect.get(repo, status))
444 state = set(hbisect.get(repo, status))
424 return subset & state
445 return subset & state
425
446
426 # Backward-compatibility
447 # Backward-compatibility
427 # - no help entry so that we do not advertise it any more
448 # - no help entry so that we do not advertise it any more
428 @predicate('bisected', safe=True)
449 @predicate('bisected', safe=True)
429 def bisected(repo, subset, x):
450 def bisected(repo, subset, x):
430 return bisect(repo, subset, x)
451 return bisect(repo, subset, x)
431
452
432 @predicate('bookmark([name])', safe=True)
453 @predicate('bookmark([name])', safe=True)
433 def bookmark(repo, subset, x):
454 def bookmark(repo, subset, x):
434 """The named bookmark or all bookmarks.
455 """The named bookmark or all bookmarks.
435
456
436 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
457 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
437 """
458 """
438 # i18n: "bookmark" is a keyword
459 # i18n: "bookmark" is a keyword
439 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
460 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
440 if args:
461 if args:
441 bm = getstring(args[0],
462 bm = getstring(args[0],
442 # i18n: "bookmark" is a keyword
463 # i18n: "bookmark" is a keyword
443 _('the argument to bookmark must be a string'))
464 _('the argument to bookmark must be a string'))
444 kind, pattern, matcher = util.stringmatcher(bm)
465 kind, pattern, matcher = util.stringmatcher(bm)
445 bms = set()
466 bms = set()
446 if kind == 'literal':
467 if kind == 'literal':
447 bmrev = repo._bookmarks.get(pattern, None)
468 bmrev = repo._bookmarks.get(pattern, None)
448 if not bmrev:
469 if not bmrev:
449 raise error.RepoLookupError(_("bookmark '%s' does not exist")
470 raise error.RepoLookupError(_("bookmark '%s' does not exist")
450 % pattern)
471 % pattern)
451 bms.add(repo[bmrev].rev())
472 bms.add(repo[bmrev].rev())
452 else:
473 else:
453 matchrevs = set()
474 matchrevs = set()
454 for name, bmrev in repo._bookmarks.iteritems():
475 for name, bmrev in repo._bookmarks.iteritems():
455 if matcher(name):
476 if matcher(name):
456 matchrevs.add(bmrev)
477 matchrevs.add(bmrev)
457 if not matchrevs:
478 if not matchrevs:
458 raise error.RepoLookupError(_("no bookmarks exist"
479 raise error.RepoLookupError(_("no bookmarks exist"
459 " that match '%s'") % pattern)
480 " that match '%s'") % pattern)
460 for bmrev in matchrevs:
481 for bmrev in matchrevs:
461 bms.add(repo[bmrev].rev())
482 bms.add(repo[bmrev].rev())
462 else:
483 else:
463 bms = {repo[r].rev() for r in repo._bookmarks.values()}
484 bms = {repo[r].rev() for r in repo._bookmarks.values()}
464 bms -= {node.nullrev}
485 bms -= {node.nullrev}
465 return subset & bms
486 return subset & bms
466
487
467 @predicate('branch(string or set)', safe=True)
488 @predicate('branch(string or set)', safe=True)
468 def branch(repo, subset, x):
489 def branch(repo, subset, x):
469 """
490 """
470 All changesets belonging to the given branch or the branches of the given
491 All changesets belonging to the given branch or the branches of the given
471 changesets.
492 changesets.
472
493
473 Pattern matching is supported for `string`. See
494 Pattern matching is supported for `string`. See
474 :hg:`help revisions.patterns`.
495 :hg:`help revisions.patterns`.
475 """
496 """
476 getbi = repo.revbranchcache().branchinfo
497 getbi = repo.revbranchcache().branchinfo
477 def getbranch(r):
498 def getbranch(r):
478 try:
499 try:
479 return getbi(r)[0]
500 return getbi(r)[0]
480 except error.WdirUnsupported:
501 except error.WdirUnsupported:
481 return repo[r].branch()
502 return repo[r].branch()
482
503
483 try:
504 try:
484 b = getstring(x, '')
505 b = getstring(x, '')
485 except error.ParseError:
506 except error.ParseError:
486 # not a string, but another revspec, e.g. tip()
507 # not a string, but another revspec, e.g. tip()
487 pass
508 pass
488 else:
509 else:
489 kind, pattern, matcher = util.stringmatcher(b)
510 kind, pattern, matcher = util.stringmatcher(b)
490 if kind == 'literal':
511 if kind == 'literal':
491 # note: falls through to the revspec case if no branch with
512 # note: falls through to the revspec case if no branch with
492 # this name exists and pattern kind is not specified explicitly
513 # this name exists and pattern kind is not specified explicitly
493 if pattern in repo.branchmap():
514 if pattern in repo.branchmap():
494 return subset.filter(lambda r: matcher(getbranch(r)),
515 return subset.filter(lambda r: matcher(getbranch(r)),
495 condrepr=('<branch %r>', b))
516 condrepr=('<branch %r>', b))
496 if b.startswith('literal:'):
517 if b.startswith('literal:'):
497 raise error.RepoLookupError(_("branch '%s' does not exist")
518 raise error.RepoLookupError(_("branch '%s' does not exist")
498 % pattern)
519 % pattern)
499 else:
520 else:
500 return subset.filter(lambda r: matcher(getbranch(r)),
521 return subset.filter(lambda r: matcher(getbranch(r)),
501 condrepr=('<branch %r>', b))
522 condrepr=('<branch %r>', b))
502
523
503 s = getset(repo, fullreposet(repo), x)
524 s = getset(repo, fullreposet(repo), x)
504 b = set()
525 b = set()
505 for r in s:
526 for r in s:
506 b.add(getbranch(r))
527 b.add(getbranch(r))
507 c = s.__contains__
528 c = s.__contains__
508 return subset.filter(lambda r: c(r) or getbranch(r) in b,
529 return subset.filter(lambda r: c(r) or getbranch(r) in b,
509 condrepr=lambda: '<branch %r>' % sorted(b))
530 condrepr=lambda: '<branch %r>' % sorted(b))
510
531
511 @predicate('bumped()', safe=True)
532 @predicate('bumped()', safe=True)
512 def bumped(repo, subset, x):
533 def bumped(repo, subset, x):
513 """Mutable changesets marked as successors of public changesets.
534 """Mutable changesets marked as successors of public changesets.
514
535
515 Only non-public and non-obsolete changesets can be `bumped`.
536 Only non-public and non-obsolete changesets can be `bumped`.
516 """
537 """
517 # i18n: "bumped" is a keyword
538 # i18n: "bumped" is a keyword
518 getargs(x, 0, 0, _("bumped takes no arguments"))
539 getargs(x, 0, 0, _("bumped takes no arguments"))
519 bumped = obsmod.getrevs(repo, 'bumped')
540 bumped = obsmod.getrevs(repo, 'bumped')
520 return subset & bumped
541 return subset & bumped
521
542
522 @predicate('bundle()', safe=True)
543 @predicate('bundle()', safe=True)
523 def bundle(repo, subset, x):
544 def bundle(repo, subset, x):
524 """Changesets in the bundle.
545 """Changesets in the bundle.
525
546
526 Bundle must be specified by the -R option."""
547 Bundle must be specified by the -R option."""
527
548
528 try:
549 try:
529 bundlerevs = repo.changelog.bundlerevs
550 bundlerevs = repo.changelog.bundlerevs
530 except AttributeError:
551 except AttributeError:
531 raise error.Abort(_("no bundle provided - specify with -R"))
552 raise error.Abort(_("no bundle provided - specify with -R"))
532 return subset & bundlerevs
553 return subset & bundlerevs
533
554
534 def checkstatus(repo, subset, pat, field):
555 def checkstatus(repo, subset, pat, field):
535 hasset = matchmod.patkind(pat) == 'set'
556 hasset = matchmod.patkind(pat) == 'set'
536
557
537 mcache = [None]
558 mcache = [None]
538 def matches(x):
559 def matches(x):
539 c = repo[x]
560 c = repo[x]
540 if not mcache[0] or hasset:
561 if not mcache[0] or hasset:
541 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
562 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
542 m = mcache[0]
563 m = mcache[0]
543 fname = None
564 fname = None
544 if not m.anypats() and len(m.files()) == 1:
565 if not m.anypats() and len(m.files()) == 1:
545 fname = m.files()[0]
566 fname = m.files()[0]
546 if fname is not None:
567 if fname is not None:
547 if fname not in c.files():
568 if fname not in c.files():
548 return False
569 return False
549 else:
570 else:
550 for f in c.files():
571 for f in c.files():
551 if m(f):
572 if m(f):
552 break
573 break
553 else:
574 else:
554 return False
575 return False
555 files = repo.status(c.p1().node(), c.node())[field]
576 files = repo.status(c.p1().node(), c.node())[field]
556 if fname is not None:
577 if fname is not None:
557 if fname in files:
578 if fname in files:
558 return True
579 return True
559 else:
580 else:
560 for f in files:
581 for f in files:
561 if m(f):
582 if m(f):
562 return True
583 return True
563
584
564 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
585 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
565
586
566 def _children(repo, subset, parentset):
587 def _children(repo, subset, parentset):
567 if not parentset:
588 if not parentset:
568 return baseset()
589 return baseset()
569 cs = set()
590 cs = set()
570 pr = repo.changelog.parentrevs
591 pr = repo.changelog.parentrevs
571 minrev = parentset.min()
592 minrev = parentset.min()
572 nullrev = node.nullrev
593 nullrev = node.nullrev
573 for r in subset:
594 for r in subset:
574 if r <= minrev:
595 if r <= minrev:
575 continue
596 continue
576 p1, p2 = pr(r)
597 p1, p2 = pr(r)
577 if p1 in parentset:
598 if p1 in parentset:
578 cs.add(r)
599 cs.add(r)
579 if p2 != nullrev and p2 in parentset:
600 if p2 != nullrev and p2 in parentset:
580 cs.add(r)
601 cs.add(r)
581 return baseset(cs)
602 return baseset(cs)
582
603
583 @predicate('children(set)', safe=True)
604 @predicate('children(set)', safe=True)
584 def children(repo, subset, x):
605 def children(repo, subset, x):
585 """Child changesets of changesets in set.
606 """Child changesets of changesets in set.
586 """
607 """
587 s = getset(repo, fullreposet(repo), x)
608 s = getset(repo, fullreposet(repo), x)
588 cs = _children(repo, subset, s)
609 cs = _children(repo, subset, s)
589 return subset & cs
610 return subset & cs
590
611
591 @predicate('closed()', safe=True)
612 @predicate('closed()', safe=True)
592 def closed(repo, subset, x):
613 def closed(repo, subset, x):
593 """Changeset is closed.
614 """Changeset is closed.
594 """
615 """
595 # i18n: "closed" is a keyword
616 # i18n: "closed" is a keyword
596 getargs(x, 0, 0, _("closed takes no arguments"))
617 getargs(x, 0, 0, _("closed takes no arguments"))
597 return subset.filter(lambda r: repo[r].closesbranch(),
618 return subset.filter(lambda r: repo[r].closesbranch(),
598 condrepr='<branch closed>')
619 condrepr='<branch closed>')
599
620
600 @predicate('contains(pattern)')
621 @predicate('contains(pattern)')
601 def contains(repo, subset, x):
622 def contains(repo, subset, x):
602 """The revision's manifest contains a file matching pattern (but might not
623 """The revision's manifest contains a file matching pattern (but might not
603 modify it). See :hg:`help patterns` for information about file patterns.
624 modify it). See :hg:`help patterns` for information about file patterns.
604
625
605 The pattern without explicit kind like ``glob:`` is expected to be
626 The pattern without explicit kind like ``glob:`` is expected to be
606 relative to the current directory and match against a file exactly
627 relative to the current directory and match against a file exactly
607 for efficiency.
628 for efficiency.
608 """
629 """
609 # i18n: "contains" is a keyword
630 # i18n: "contains" is a keyword
610 pat = getstring(x, _("contains requires a pattern"))
631 pat = getstring(x, _("contains requires a pattern"))
611
632
612 def matches(x):
633 def matches(x):
613 if not matchmod.patkind(pat):
634 if not matchmod.patkind(pat):
614 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
635 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
615 if pats in repo[x]:
636 if pats in repo[x]:
616 return True
637 return True
617 else:
638 else:
618 c = repo[x]
639 c = repo[x]
619 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
640 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
620 for f in c.manifest():
641 for f in c.manifest():
621 if m(f):
642 if m(f):
622 return True
643 return True
623 return False
644 return False
624
645
625 return subset.filter(matches, condrepr=('<contains %r>', pat))
646 return subset.filter(matches, condrepr=('<contains %r>', pat))
626
647
627 @predicate('converted([id])', safe=True)
648 @predicate('converted([id])', safe=True)
628 def converted(repo, subset, x):
649 def converted(repo, subset, x):
629 """Changesets converted from the given identifier in the old repository if
650 """Changesets converted from the given identifier in the old repository if
630 present, or all converted changesets if no identifier is specified.
651 present, or all converted changesets if no identifier is specified.
631 """
652 """
632
653
633 # There is exactly no chance of resolving the revision, so do a simple
654 # There is exactly no chance of resolving the revision, so do a simple
634 # string compare and hope for the best
655 # string compare and hope for the best
635
656
636 rev = None
657 rev = None
637 # i18n: "converted" is a keyword
658 # i18n: "converted" is a keyword
638 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
659 l = getargs(x, 0, 1, _('converted takes one or no arguments'))
639 if l:
660 if l:
640 # i18n: "converted" is a keyword
661 # i18n: "converted" is a keyword
641 rev = getstring(l[0], _('converted requires a revision'))
662 rev = getstring(l[0], _('converted requires a revision'))
642
663
643 def _matchvalue(r):
664 def _matchvalue(r):
644 source = repo[r].extra().get('convert_revision', None)
665 source = repo[r].extra().get('convert_revision', None)
645 return source is not None and (rev is None or source.startswith(rev))
666 return source is not None and (rev is None or source.startswith(rev))
646
667
647 return subset.filter(lambda r: _matchvalue(r),
668 return subset.filter(lambda r: _matchvalue(r),
648 condrepr=('<converted %r>', rev))
669 condrepr=('<converted %r>', rev))
649
670
650 @predicate('date(interval)', safe=True)
671 @predicate('date(interval)', safe=True)
651 def date(repo, subset, x):
672 def date(repo, subset, x):
652 """Changesets within the interval, see :hg:`help dates`.
673 """Changesets within the interval, see :hg:`help dates`.
653 """
674 """
654 # i18n: "date" is a keyword
675 # i18n: "date" is a keyword
655 ds = getstring(x, _("date requires a string"))
676 ds = getstring(x, _("date requires a string"))
656 dm = util.matchdate(ds)
677 dm = util.matchdate(ds)
657 return subset.filter(lambda x: dm(repo[x].date()[0]),
678 return subset.filter(lambda x: dm(repo[x].date()[0]),
658 condrepr=('<date %r>', ds))
679 condrepr=('<date %r>', ds))
659
680
660 @predicate('desc(string)', safe=True)
681 @predicate('desc(string)', safe=True)
661 def desc(repo, subset, x):
682 def desc(repo, subset, x):
662 """Search commit message for string. The match is case-insensitive.
683 """Search commit message for string. The match is case-insensitive.
663
684
664 Pattern matching is supported for `string`. See
685 Pattern matching is supported for `string`. See
665 :hg:`help revisions.patterns`.
686 :hg:`help revisions.patterns`.
666 """
687 """
667 # i18n: "desc" is a keyword
688 # i18n: "desc" is a keyword
668 ds = getstring(x, _("desc requires a string"))
689 ds = getstring(x, _("desc requires a string"))
669
690
670 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
691 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
671
692
672 return subset.filter(lambda r: matcher(repo[r].description()),
693 return subset.filter(lambda r: matcher(repo[r].description()),
673 condrepr=('<desc %r>', ds))
694 condrepr=('<desc %r>', ds))
674
695
675 def _descendants(repo, subset, x, followfirst=False):
696 def _descendants(repo, subset, x, followfirst=False):
676 roots = getset(repo, fullreposet(repo), x)
697 roots = getset(repo, fullreposet(repo), x)
677 if not roots:
698 if not roots:
678 return baseset()
699 return baseset()
679 s = _revdescendants(repo, roots, followfirst)
700 s = _revdescendants(repo, roots, followfirst)
680
701
681 # Both sets need to be ascending in order to lazily return the union
702 # Both sets need to be ascending in order to lazily return the union
682 # in the correct order.
703 # in the correct order.
683 base = subset & roots
704 base = subset & roots
684 desc = subset & s
705 desc = subset & s
685 result = base + desc
706 result = base + desc
686 if subset.isascending():
707 if subset.isascending():
687 result.sort()
708 result.sort()
688 elif subset.isdescending():
709 elif subset.isdescending():
689 result.sort(reverse=True)
710 result.sort(reverse=True)
690 else:
711 else:
691 result = subset & result
712 result = subset & result
692 return result
713 return result
693
714
694 @predicate('descendants(set)', safe=True)
715 @predicate('descendants(set)', safe=True)
695 def descendants(repo, subset, x):
716 def descendants(repo, subset, x):
696 """Changesets which are descendants of changesets in set.
717 """Changesets which are descendants of changesets in set.
697 """
718 """
698 return _descendants(repo, subset, x)
719 return _descendants(repo, subset, x)
699
720
700 @predicate('_firstdescendants', safe=True)
721 @predicate('_firstdescendants', safe=True)
701 def _firstdescendants(repo, subset, x):
722 def _firstdescendants(repo, subset, x):
702 # ``_firstdescendants(set)``
723 # ``_firstdescendants(set)``
703 # Like ``descendants(set)`` but follows only the first parents.
724 # Like ``descendants(set)`` but follows only the first parents.
704 return _descendants(repo, subset, x, followfirst=True)
725 return _descendants(repo, subset, x, followfirst=True)
705
726
706 @predicate('destination([set])', safe=True)
727 @predicate('destination([set])', safe=True)
707 def destination(repo, subset, x):
728 def destination(repo, subset, x):
708 """Changesets that were created by a graft, transplant or rebase operation,
729 """Changesets that were created by a graft, transplant or rebase operation,
709 with the given revisions specified as the source. Omitting the optional set
730 with the given revisions specified as the source. Omitting the optional set
710 is the same as passing all().
731 is the same as passing all().
711 """
732 """
712 if x is not None:
733 if x is not None:
713 sources = getset(repo, fullreposet(repo), x)
734 sources = getset(repo, fullreposet(repo), x)
714 else:
735 else:
715 sources = fullreposet(repo)
736 sources = fullreposet(repo)
716
737
717 dests = set()
738 dests = set()
718
739
719 # subset contains all of the possible destinations that can be returned, so
740 # subset contains all of the possible destinations that can be returned, so
720 # iterate over them and see if their source(s) were provided in the arg set.
741 # iterate over them and see if their source(s) were provided in the arg set.
721 # Even if the immediate src of r is not in the arg set, src's source (or
742 # Even if the immediate src of r is not in the arg set, src's source (or
722 # further back) may be. Scanning back further than the immediate src allows
743 # further back) may be. Scanning back further than the immediate src allows
723 # transitive transplants and rebases to yield the same results as transitive
744 # transitive transplants and rebases to yield the same results as transitive
724 # grafts.
745 # grafts.
725 for r in subset:
746 for r in subset:
726 src = _getrevsource(repo, r)
747 src = _getrevsource(repo, r)
727 lineage = None
748 lineage = None
728
749
729 while src is not None:
750 while src is not None:
730 if lineage is None:
751 if lineage is None:
731 lineage = list()
752 lineage = list()
732
753
733 lineage.append(r)
754 lineage.append(r)
734
755
735 # The visited lineage is a match if the current source is in the arg
756 # The visited lineage is a match if the current source is in the arg
736 # set. Since every candidate dest is visited by way of iterating
757 # set. Since every candidate dest is visited by way of iterating
737 # subset, any dests further back in the lineage will be tested by a
758 # subset, any dests further back in the lineage will be tested by a
738 # different iteration over subset. Likewise, if the src was already
759 # different iteration over subset. Likewise, if the src was already
739 # selected, the current lineage can be selected without going back
760 # selected, the current lineage can be selected without going back
740 # further.
761 # further.
741 if src in sources or src in dests:
762 if src in sources or src in dests:
742 dests.update(lineage)
763 dests.update(lineage)
743 break
764 break
744
765
745 r = src
766 r = src
746 src = _getrevsource(repo, r)
767 src = _getrevsource(repo, r)
747
768
748 return subset.filter(dests.__contains__,
769 return subset.filter(dests.__contains__,
749 condrepr=lambda: '<destination %r>' % sorted(dests))
770 condrepr=lambda: '<destination %r>' % sorted(dests))
750
771
751 @predicate('divergent()', safe=True)
772 @predicate('divergent()', safe=True)
752 def divergent(repo, subset, x):
773 def divergent(repo, subset, x):
753 """
774 """
754 Final successors of changesets with an alternative set of final successors.
775 Final successors of changesets with an alternative set of final successors.
755 """
776 """
756 # i18n: "divergent" is a keyword
777 # i18n: "divergent" is a keyword
757 getargs(x, 0, 0, _("divergent takes no arguments"))
778 getargs(x, 0, 0, _("divergent takes no arguments"))
758 divergent = obsmod.getrevs(repo, 'divergent')
779 divergent = obsmod.getrevs(repo, 'divergent')
759 return subset & divergent
780 return subset & divergent
760
781
761 @predicate('extinct()', safe=True)
782 @predicate('extinct()', safe=True)
762 def extinct(repo, subset, x):
783 def extinct(repo, subset, x):
763 """Obsolete changesets with obsolete descendants only.
784 """Obsolete changesets with obsolete descendants only.
764 """
785 """
765 # i18n: "extinct" is a keyword
786 # i18n: "extinct" is a keyword
766 getargs(x, 0, 0, _("extinct takes no arguments"))
787 getargs(x, 0, 0, _("extinct takes no arguments"))
767 extincts = obsmod.getrevs(repo, 'extinct')
788 extincts = obsmod.getrevs(repo, 'extinct')
768 return subset & extincts
789 return subset & extincts
769
790
770 @predicate('extra(label, [value])', safe=True)
791 @predicate('extra(label, [value])', safe=True)
771 def extra(repo, subset, x):
792 def extra(repo, subset, x):
772 """Changesets with the given label in the extra metadata, with the given
793 """Changesets with the given label in the extra metadata, with the given
773 optional value.
794 optional value.
774
795
775 Pattern matching is supported for `value`. See
796 Pattern matching is supported for `value`. See
776 :hg:`help revisions.patterns`.
797 :hg:`help revisions.patterns`.
777 """
798 """
778 args = getargsdict(x, 'extra', 'label value')
799 args = getargsdict(x, 'extra', 'label value')
779 if 'label' not in args:
800 if 'label' not in args:
780 # i18n: "extra" is a keyword
801 # i18n: "extra" is a keyword
781 raise error.ParseError(_('extra takes at least 1 argument'))
802 raise error.ParseError(_('extra takes at least 1 argument'))
782 # i18n: "extra" is a keyword
803 # i18n: "extra" is a keyword
783 label = getstring(args['label'], _('first argument to extra must be '
804 label = getstring(args['label'], _('first argument to extra must be '
784 'a string'))
805 'a string'))
785 value = None
806 value = None
786
807
787 if 'value' in args:
808 if 'value' in args:
788 # i18n: "extra" is a keyword
809 # i18n: "extra" is a keyword
789 value = getstring(args['value'], _('second argument to extra must be '
810 value = getstring(args['value'], _('second argument to extra must be '
790 'a string'))
811 'a string'))
791 kind, value, matcher = util.stringmatcher(value)
812 kind, value, matcher = util.stringmatcher(value)
792
813
793 def _matchvalue(r):
814 def _matchvalue(r):
794 extra = repo[r].extra()
815 extra = repo[r].extra()
795 return label in extra and (value is None or matcher(extra[label]))
816 return label in extra and (value is None or matcher(extra[label]))
796
817
797 return subset.filter(lambda r: _matchvalue(r),
818 return subset.filter(lambda r: _matchvalue(r),
798 condrepr=('<extra[%r] %r>', label, value))
819 condrepr=('<extra[%r] %r>', label, value))
799
820
800 @predicate('filelog(pattern)', safe=True)
821 @predicate('filelog(pattern)', safe=True)
801 def filelog(repo, subset, x):
822 def filelog(repo, subset, x):
802 """Changesets connected to the specified filelog.
823 """Changesets connected to the specified filelog.
803
824
804 For performance reasons, visits only revisions mentioned in the file-level
825 For performance reasons, visits only revisions mentioned in the file-level
805 filelog, rather than filtering through all changesets (much faster, but
826 filelog, rather than filtering through all changesets (much faster, but
806 doesn't include deletes or duplicate changes). For a slower, more accurate
827 doesn't include deletes or duplicate changes). For a slower, more accurate
807 result, use ``file()``.
828 result, use ``file()``.
808
829
809 The pattern without explicit kind like ``glob:`` is expected to be
830 The pattern without explicit kind like ``glob:`` is expected to be
810 relative to the current directory and match against a file exactly
831 relative to the current directory and match against a file exactly
811 for efficiency.
832 for efficiency.
812
833
813 If some linkrev points to revisions filtered by the current repoview, we'll
834 If some linkrev points to revisions filtered by the current repoview, we'll
814 work around it to return a non-filtered value.
835 work around it to return a non-filtered value.
815 """
836 """
816
837
817 # i18n: "filelog" is a keyword
838 # i18n: "filelog" is a keyword
818 pat = getstring(x, _("filelog requires a pattern"))
839 pat = getstring(x, _("filelog requires a pattern"))
819 s = set()
840 s = set()
820 cl = repo.changelog
841 cl = repo.changelog
821
842
822 if not matchmod.patkind(pat):
843 if not matchmod.patkind(pat):
823 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
844 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
824 files = [f]
845 files = [f]
825 else:
846 else:
826 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
847 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
827 files = (f for f in repo[None] if m(f))
848 files = (f for f in repo[None] if m(f))
828
849
829 for f in files:
850 for f in files:
830 fl = repo.file(f)
851 fl = repo.file(f)
831 known = {}
852 known = {}
832 scanpos = 0
853 scanpos = 0
833 for fr in list(fl):
854 for fr in list(fl):
834 fn = fl.node(fr)
855 fn = fl.node(fr)
835 if fn in known:
856 if fn in known:
836 s.add(known[fn])
857 s.add(known[fn])
837 continue
858 continue
838
859
839 lr = fl.linkrev(fr)
860 lr = fl.linkrev(fr)
840 if lr in cl:
861 if lr in cl:
841 s.add(lr)
862 s.add(lr)
842 elif scanpos is not None:
863 elif scanpos is not None:
843 # lowest matching changeset is filtered, scan further
864 # lowest matching changeset is filtered, scan further
844 # ahead in changelog
865 # ahead in changelog
845 start = max(lr, scanpos) + 1
866 start = max(lr, scanpos) + 1
846 scanpos = None
867 scanpos = None
847 for r in cl.revs(start):
868 for r in cl.revs(start):
848 # minimize parsing of non-matching entries
869 # minimize parsing of non-matching entries
849 if f in cl.revision(r) and f in cl.readfiles(r):
870 if f in cl.revision(r) and f in cl.readfiles(r):
850 try:
871 try:
851 # try to use manifest delta fastpath
872 # try to use manifest delta fastpath
852 n = repo[r].filenode(f)
873 n = repo[r].filenode(f)
853 if n not in known:
874 if n not in known:
854 if n == fn:
875 if n == fn:
855 s.add(r)
876 s.add(r)
856 scanpos = r
877 scanpos = r
857 break
878 break
858 else:
879 else:
859 known[n] = r
880 known[n] = r
860 except error.ManifestLookupError:
881 except error.ManifestLookupError:
861 # deletion in changelog
882 # deletion in changelog
862 continue
883 continue
863
884
864 return subset & s
885 return subset & s
865
886
866 @predicate('first(set, [n])', safe=True)
887 @predicate('first(set, [n])', safe=True)
867 def first(repo, subset, x):
888 def first(repo, subset, x):
868 """An alias for limit().
889 """An alias for limit().
869 """
890 """
870 return limit(repo, subset, x)
891 return limit(repo, subset, x)
871
892
872 def _follow(repo, subset, x, name, followfirst=False):
893 def _follow(repo, subset, x, name, followfirst=False):
873 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
894 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
874 "and an optional revset") % name)
895 "and an optional revset") % name)
875 c = repo['.']
896 c = repo['.']
876 if l:
897 if l:
877 x = getstring(l[0], _("%s expected a pattern") % name)
898 x = getstring(l[0], _("%s expected a pattern") % name)
878 rev = None
899 rev = None
879 if len(l) >= 2:
900 if len(l) >= 2:
880 revs = getset(repo, fullreposet(repo), l[1])
901 revs = getset(repo, fullreposet(repo), l[1])
881 if len(revs) != 1:
902 if len(revs) != 1:
882 raise error.RepoLookupError(
903 raise error.RepoLookupError(
883 _("%s expected one starting revision") % name)
904 _("%s expected one starting revision") % name)
884 rev = revs.last()
905 rev = revs.last()
885 c = repo[rev]
906 c = repo[rev]
886 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
907 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
887 ctx=repo[rev], default='path')
908 ctx=repo[rev], default='path')
888
909
889 files = c.manifest().walk(matcher)
910 files = c.manifest().walk(matcher)
890
911
891 s = set()
912 s = set()
892 for fname in files:
913 for fname in files:
893 fctx = c[fname]
914 fctx = c[fname]
894 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
915 s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
895 # include the revision responsible for the most recent version
916 # include the revision responsible for the most recent version
896 s.add(fctx.introrev())
917 s.add(fctx.introrev())
897 else:
918 else:
898 s = _revancestors(repo, baseset([c.rev()]), followfirst)
919 s = _revancestors(repo, baseset([c.rev()]), followfirst)
899
920
900 return subset & s
921 return subset & s
901
922
902 @predicate('follow([pattern[, startrev]])', safe=True)
923 @predicate('follow([pattern[, startrev]])', safe=True)
903 def follow(repo, subset, x):
924 def follow(repo, subset, x):
904 """
925 """
905 An alias for ``::.`` (ancestors of the working directory's first parent).
926 An alias for ``::.`` (ancestors of the working directory's first parent).
906 If pattern is specified, the histories of files matching given
927 If pattern is specified, the histories of files matching given
907 pattern in the revision given by startrev are followed, including copies.
928 pattern in the revision given by startrev are followed, including copies.
908 """
929 """
909 return _follow(repo, subset, x, 'follow')
930 return _follow(repo, subset, x, 'follow')
910
931
911 @predicate('_followfirst', safe=True)
932 @predicate('_followfirst', safe=True)
912 def _followfirst(repo, subset, x):
933 def _followfirst(repo, subset, x):
913 # ``followfirst([pattern[, startrev]])``
934 # ``followfirst([pattern[, startrev]])``
914 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
935 # Like ``follow([pattern[, startrev]])`` but follows only the first parent
915 # of every revisions or files revisions.
936 # of every revisions or files revisions.
916 return _follow(repo, subset, x, '_followfirst', followfirst=True)
937 return _follow(repo, subset, x, '_followfirst', followfirst=True)
917
938
918 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
939 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])',
919 safe=True)
940 safe=True)
920 def followlines(repo, subset, x):
941 def followlines(repo, subset, x):
921 """Changesets modifying `file` in line range ('fromline', 'toline').
942 """Changesets modifying `file` in line range ('fromline', 'toline').
922
943
923 Line range corresponds to 'file' content at 'startrev' and should hence be
944 Line range corresponds to 'file' content at 'startrev' and should hence be
924 consistent with file size. If startrev is not specified, working directory's
945 consistent with file size. If startrev is not specified, working directory's
925 parent is used.
946 parent is used.
926
947
927 By default, ancestors of 'startrev' are returned. If 'descend' is True,
948 By default, ancestors of 'startrev' are returned. If 'descend' is True,
928 descendants of 'startrev' are returned though renames are (currently) not
949 descendants of 'startrev' are returned though renames are (currently) not
929 followed in this direction.
950 followed in this direction.
930 """
951 """
931 from . import context # avoid circular import issues
952 from . import context # avoid circular import issues
932
953
933 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
954 args = getargsdict(x, 'followlines', 'file *lines startrev descend')
934 if len(args['lines']) != 1:
955 if len(args['lines']) != 1:
935 raise error.ParseError(_("followlines requires a line range"))
956 raise error.ParseError(_("followlines requires a line range"))
936
957
937 rev = '.'
958 rev = '.'
938 if 'startrev' in args:
959 if 'startrev' in args:
939 revs = getset(repo, fullreposet(repo), args['startrev'])
960 revs = getset(repo, fullreposet(repo), args['startrev'])
940 if len(revs) != 1:
961 if len(revs) != 1:
941 raise error.ParseError(
962 raise error.ParseError(
942 # i18n: "followlines" is a keyword
963 # i18n: "followlines" is a keyword
943 _("followlines expects exactly one revision"))
964 _("followlines expects exactly one revision"))
944 rev = revs.last()
965 rev = revs.last()
945
966
946 pat = getstring(args['file'], _("followlines requires a pattern"))
967 pat = getstring(args['file'], _("followlines requires a pattern"))
947 if not matchmod.patkind(pat):
968 if not matchmod.patkind(pat):
948 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
969 fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
949 else:
970 else:
950 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
971 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
951 files = [f for f in repo[rev] if m(f)]
972 files = [f for f in repo[rev] if m(f)]
952 if len(files) != 1:
973 if len(files) != 1:
953 # i18n: "followlines" is a keyword
974 # i18n: "followlines" is a keyword
954 raise error.ParseError(_("followlines expects exactly one file"))
975 raise error.ParseError(_("followlines expects exactly one file"))
955 fname = files[0]
976 fname = files[0]
956
977
957 # i18n: "followlines" is a keyword
978 # i18n: "followlines" is a keyword
958 lr = getrange(args['lines'][0], _("followlines expects a line range"))
979 lr = getrange(args['lines'][0], _("followlines expects a line range"))
959 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
980 fromline, toline = [getinteger(a, _("line range bounds must be integers"))
960 for a in lr]
981 for a in lr]
961 fromline, toline = util.processlinerange(fromline, toline)
982 fromline, toline = util.processlinerange(fromline, toline)
962
983
963 fctx = repo[rev].filectx(fname)
984 fctx = repo[rev].filectx(fname)
964 descend = False
985 descend = False
965 if 'descend' in args:
986 if 'descend' in args:
966 descend = getboolean(args['descend'],
987 descend = getboolean(args['descend'],
967 # i18n: "descend" is a keyword
988 # i18n: "descend" is a keyword
968 _("descend argument must be a boolean"))
989 _("descend argument must be a boolean"))
969 if descend:
990 if descend:
970 rs = generatorset(
991 rs = generatorset(
971 (c.rev() for c, _linerange
992 (c.rev() for c, _linerange
972 in context.blockdescendants(fctx, fromline, toline)),
993 in context.blockdescendants(fctx, fromline, toline)),
973 iterasc=True)
994 iterasc=True)
974 else:
995 else:
975 rs = generatorset(
996 rs = generatorset(
976 (c.rev() for c, _linerange
997 (c.rev() for c, _linerange
977 in context.blockancestors(fctx, fromline, toline)),
998 in context.blockancestors(fctx, fromline, toline)),
978 iterasc=False)
999 iterasc=False)
979 return subset & rs
1000 return subset & rs
980
1001
981 @predicate('all()', safe=True)
1002 @predicate('all()', safe=True)
982 def getall(repo, subset, x):
1003 def getall(repo, subset, x):
983 """All changesets, the same as ``0:tip``.
1004 """All changesets, the same as ``0:tip``.
984 """
1005 """
985 # i18n: "all" is a keyword
1006 # i18n: "all" is a keyword
986 getargs(x, 0, 0, _("all takes no arguments"))
1007 getargs(x, 0, 0, _("all takes no arguments"))
987 return subset & spanset(repo) # drop "null" if any
1008 return subset & spanset(repo) # drop "null" if any
988
1009
989 @predicate('grep(regex)')
1010 @predicate('grep(regex)')
990 def grep(repo, subset, x):
1011 def grep(repo, subset, x):
991 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1012 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
992 to ensure special escape characters are handled correctly. Unlike
1013 to ensure special escape characters are handled correctly. Unlike
993 ``keyword(string)``, the match is case-sensitive.
1014 ``keyword(string)``, the match is case-sensitive.
994 """
1015 """
995 try:
1016 try:
996 # i18n: "grep" is a keyword
1017 # i18n: "grep" is a keyword
997 gr = re.compile(getstring(x, _("grep requires a string")))
1018 gr = re.compile(getstring(x, _("grep requires a string")))
998 except re.error as e:
1019 except re.error as e:
999 raise error.ParseError(_('invalid match pattern: %s') % e)
1020 raise error.ParseError(_('invalid match pattern: %s') % e)
1000
1021
1001 def matches(x):
1022 def matches(x):
1002 c = repo[x]
1023 c = repo[x]
1003 for e in c.files() + [c.user(), c.description()]:
1024 for e in c.files() + [c.user(), c.description()]:
1004 if gr.search(e):
1025 if gr.search(e):
1005 return True
1026 return True
1006 return False
1027 return False
1007
1028
1008 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
1029 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
1009
1030
1010 @predicate('_matchfiles', safe=True)
1031 @predicate('_matchfiles', safe=True)
1011 def _matchfiles(repo, subset, x):
1032 def _matchfiles(repo, subset, x):
1012 # _matchfiles takes a revset list of prefixed arguments:
1033 # _matchfiles takes a revset list of prefixed arguments:
1013 #
1034 #
1014 # [p:foo, i:bar, x:baz]
1035 # [p:foo, i:bar, x:baz]
1015 #
1036 #
1016 # builds a match object from them and filters subset. Allowed
1037 # builds a match object from them and filters subset. Allowed
1017 # prefixes are 'p:' for regular patterns, 'i:' for include
1038 # prefixes are 'p:' for regular patterns, 'i:' for include
1018 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1039 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
1019 # a revision identifier, or the empty string to reference the
1040 # a revision identifier, or the empty string to reference the
1020 # working directory, from which the match object is
1041 # working directory, from which the match object is
1021 # initialized. Use 'd:' to set the default matching mode, default
1042 # initialized. Use 'd:' to set the default matching mode, default
1022 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1043 # to 'glob'. At most one 'r:' and 'd:' argument can be passed.
1023
1044
1024 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1045 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
1025 pats, inc, exc = [], [], []
1046 pats, inc, exc = [], [], []
1026 rev, default = None, None
1047 rev, default = None, None
1027 for arg in l:
1048 for arg in l:
1028 s = getstring(arg, "_matchfiles requires string arguments")
1049 s = getstring(arg, "_matchfiles requires string arguments")
1029 prefix, value = s[:2], s[2:]
1050 prefix, value = s[:2], s[2:]
1030 if prefix == 'p:':
1051 if prefix == 'p:':
1031 pats.append(value)
1052 pats.append(value)
1032 elif prefix == 'i:':
1053 elif prefix == 'i:':
1033 inc.append(value)
1054 inc.append(value)
1034 elif prefix == 'x:':
1055 elif prefix == 'x:':
1035 exc.append(value)
1056 exc.append(value)
1036 elif prefix == 'r:':
1057 elif prefix == 'r:':
1037 if rev is not None:
1058 if rev is not None:
1038 raise error.ParseError('_matchfiles expected at most one '
1059 raise error.ParseError('_matchfiles expected at most one '
1039 'revision')
1060 'revision')
1040 if value != '': # empty means working directory; leave rev as None
1061 if value != '': # empty means working directory; leave rev as None
1041 rev = value
1062 rev = value
1042 elif prefix == 'd:':
1063 elif prefix == 'd:':
1043 if default is not None:
1064 if default is not None:
1044 raise error.ParseError('_matchfiles expected at most one '
1065 raise error.ParseError('_matchfiles expected at most one '
1045 'default mode')
1066 'default mode')
1046 default = value
1067 default = value
1047 else:
1068 else:
1048 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1069 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1049 if not default:
1070 if not default:
1050 default = 'glob'
1071 default = 'glob'
1051
1072
1052 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1073 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
1053 exclude=exc, ctx=repo[rev], default=default)
1074 exclude=exc, ctx=repo[rev], default=default)
1054
1075
1055 # This directly read the changelog data as creating changectx for all
1076 # This directly read the changelog data as creating changectx for all
1056 # revisions is quite expensive.
1077 # revisions is quite expensive.
1057 getfiles = repo.changelog.readfiles
1078 getfiles = repo.changelog.readfiles
1058 wdirrev = node.wdirrev
1079 wdirrev = node.wdirrev
1059 def matches(x):
1080 def matches(x):
1060 if x == wdirrev:
1081 if x == wdirrev:
1061 files = repo[x].files()
1082 files = repo[x].files()
1062 else:
1083 else:
1063 files = getfiles(x)
1084 files = getfiles(x)
1064 for f in files:
1085 for f in files:
1065 if m(f):
1086 if m(f):
1066 return True
1087 return True
1067 return False
1088 return False
1068
1089
1069 return subset.filter(matches,
1090 return subset.filter(matches,
1070 condrepr=('<matchfiles patterns=%r, include=%r '
1091 condrepr=('<matchfiles patterns=%r, include=%r '
1071 'exclude=%r, default=%r, rev=%r>',
1092 'exclude=%r, default=%r, rev=%r>',
1072 pats, inc, exc, default, rev))
1093 pats, inc, exc, default, rev))
1073
1094
1074 @predicate('file(pattern)', safe=True)
1095 @predicate('file(pattern)', safe=True)
1075 def hasfile(repo, subset, x):
1096 def hasfile(repo, subset, x):
1076 """Changesets affecting files matched by pattern.
1097 """Changesets affecting files matched by pattern.
1077
1098
1078 For a faster but less accurate result, consider using ``filelog()``
1099 For a faster but less accurate result, consider using ``filelog()``
1079 instead.
1100 instead.
1080
1101
1081 This predicate uses ``glob:`` as the default kind of pattern.
1102 This predicate uses ``glob:`` as the default kind of pattern.
1082 """
1103 """
1083 # i18n: "file" is a keyword
1104 # i18n: "file" is a keyword
1084 pat = getstring(x, _("file requires a pattern"))
1105 pat = getstring(x, _("file requires a pattern"))
1085 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1106 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1086
1107
1087 @predicate('head()', safe=True)
1108 @predicate('head()', safe=True)
1088 def head(repo, subset, x):
1109 def head(repo, subset, x):
1089 """Changeset is a named branch head.
1110 """Changeset is a named branch head.
1090 """
1111 """
1091 # i18n: "head" is a keyword
1112 # i18n: "head" is a keyword
1092 getargs(x, 0, 0, _("head takes no arguments"))
1113 getargs(x, 0, 0, _("head takes no arguments"))
1093 hs = set()
1114 hs = set()
1094 cl = repo.changelog
1115 cl = repo.changelog
1095 for ls in repo.branchmap().itervalues():
1116 for ls in repo.branchmap().itervalues():
1096 hs.update(cl.rev(h) for h in ls)
1117 hs.update(cl.rev(h) for h in ls)
1097 return subset & baseset(hs)
1118 return subset & baseset(hs)
1098
1119
1099 @predicate('heads(set)', safe=True)
1120 @predicate('heads(set)', safe=True)
1100 def heads(repo, subset, x):
1121 def heads(repo, subset, x):
1101 """Members of set with no children in set.
1122 """Members of set with no children in set.
1102 """
1123 """
1103 s = getset(repo, subset, x)
1124 s = getset(repo, subset, x)
1104 ps = parents(repo, subset, x)
1125 ps = parents(repo, subset, x)
1105 return s - ps
1126 return s - ps
1106
1127
1107 @predicate('hidden()', safe=True)
1128 @predicate('hidden()', safe=True)
1108 def hidden(repo, subset, x):
1129 def hidden(repo, subset, x):
1109 """Hidden changesets.
1130 """Hidden changesets.
1110 """
1131 """
1111 # i18n: "hidden" is a keyword
1132 # i18n: "hidden" is a keyword
1112 getargs(x, 0, 0, _("hidden takes no arguments"))
1133 getargs(x, 0, 0, _("hidden takes no arguments"))
1113 hiddenrevs = repoview.filterrevs(repo, 'visible')
1134 hiddenrevs = repoview.filterrevs(repo, 'visible')
1114 return subset & hiddenrevs
1135 return subset & hiddenrevs
1115
1136
1116 @predicate('keyword(string)', safe=True)
1137 @predicate('keyword(string)', safe=True)
1117 def keyword(repo, subset, x):
1138 def keyword(repo, subset, x):
1118 """Search commit message, user name, and names of changed files for
1139 """Search commit message, user name, and names of changed files for
1119 string. The match is case-insensitive.
1140 string. The match is case-insensitive.
1120
1141
1121 For a regular expression or case sensitive search of these fields, use
1142 For a regular expression or case sensitive search of these fields, use
1122 ``grep(regex)``.
1143 ``grep(regex)``.
1123 """
1144 """
1124 # i18n: "keyword" is a keyword
1145 # i18n: "keyword" is a keyword
1125 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1146 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1126
1147
1127 def matches(r):
1148 def matches(r):
1128 c = repo[r]
1149 c = repo[r]
1129 return any(kw in encoding.lower(t)
1150 return any(kw in encoding.lower(t)
1130 for t in c.files() + [c.user(), c.description()])
1151 for t in c.files() + [c.user(), c.description()])
1131
1152
1132 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1153 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1133
1154
1134 @predicate('limit(set[, n[, offset]])', safe=True)
1155 @predicate('limit(set[, n[, offset]])', safe=True)
1135 def limit(repo, subset, x):
1156 def limit(repo, subset, x):
1136 """First n members of set, defaulting to 1, starting from offset.
1157 """First n members of set, defaulting to 1, starting from offset.
1137 """
1158 """
1138 args = getargsdict(x, 'limit', 'set n offset')
1159 args = getargsdict(x, 'limit', 'set n offset')
1139 if 'set' not in args:
1160 if 'set' not in args:
1140 # i18n: "limit" is a keyword
1161 # i18n: "limit" is a keyword
1141 raise error.ParseError(_("limit requires one to three arguments"))
1162 raise error.ParseError(_("limit requires one to three arguments"))
1142 # i18n: "limit" is a keyword
1163 # i18n: "limit" is a keyword
1143 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1164 lim = getinteger(args.get('n'), _("limit expects a number"), default=1)
1144 # i18n: "limit" is a keyword
1165 # i18n: "limit" is a keyword
1145 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1166 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0)
1146 if ofs < 0:
1167 if ofs < 0:
1147 raise error.ParseError(_("negative offset"))
1168 raise error.ParseError(_("negative offset"))
1148 os = getset(repo, fullreposet(repo), args['set'])
1169 os = getset(repo, fullreposet(repo), args['set'])
1149 result = []
1170 result = []
1150 it = iter(os)
1171 it = iter(os)
1151 for x in xrange(ofs):
1172 for x in xrange(ofs):
1152 y = next(it, None)
1173 y = next(it, None)
1153 if y is None:
1174 if y is None:
1154 break
1175 break
1155 for x in xrange(lim):
1176 for x in xrange(lim):
1156 y = next(it, None)
1177 y = next(it, None)
1157 if y is None:
1178 if y is None:
1158 break
1179 break
1159 elif y in subset:
1180 elif y in subset:
1160 result.append(y)
1181 result.append(y)
1161 return baseset(result, datarepr=('<limit n=%d, offset=%d, %r, %r>',
1182 return baseset(result, datarepr=('<limit n=%d, offset=%d, %r, %r>',
1162 lim, ofs, subset, os))
1183 lim, ofs, subset, os))
1163
1184
1164 @predicate('last(set, [n])', safe=True)
1185 @predicate('last(set, [n])', safe=True)
1165 def last(repo, subset, x):
1186 def last(repo, subset, x):
1166 """Last n members of set, defaulting to 1.
1187 """Last n members of set, defaulting to 1.
1167 """
1188 """
1168 # i18n: "last" is a keyword
1189 # i18n: "last" is a keyword
1169 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1190 l = getargs(x, 1, 2, _("last requires one or two arguments"))
1170 lim = 1
1191 lim = 1
1171 if len(l) == 2:
1192 if len(l) == 2:
1172 # i18n: "last" is a keyword
1193 # i18n: "last" is a keyword
1173 lim = getinteger(l[1], _("last expects a number"))
1194 lim = getinteger(l[1], _("last expects a number"))
1174 os = getset(repo, fullreposet(repo), l[0])
1195 os = getset(repo, fullreposet(repo), l[0])
1175 os.reverse()
1196 os.reverse()
1176 result = []
1197 result = []
1177 it = iter(os)
1198 it = iter(os)
1178 for x in xrange(lim):
1199 for x in xrange(lim):
1179 y = next(it, None)
1200 y = next(it, None)
1180 if y is None:
1201 if y is None:
1181 break
1202 break
1182 elif y in subset:
1203 elif y in subset:
1183 result.append(y)
1204 result.append(y)
1184 return baseset(result, datarepr=('<last n=%d, %r, %r>', lim, subset, os))
1205 return baseset(result, datarepr=('<last n=%d, %r, %r>', lim, subset, os))
1185
1206
1186 @predicate('max(set)', safe=True)
1207 @predicate('max(set)', safe=True)
1187 def maxrev(repo, subset, x):
1208 def maxrev(repo, subset, x):
1188 """Changeset with highest revision number in set.
1209 """Changeset with highest revision number in set.
1189 """
1210 """
1190 os = getset(repo, fullreposet(repo), x)
1211 os = getset(repo, fullreposet(repo), x)
1191 try:
1212 try:
1192 m = os.max()
1213 m = os.max()
1193 if m in subset:
1214 if m in subset:
1194 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1215 return baseset([m], datarepr=('<max %r, %r>', subset, os))
1195 except ValueError:
1216 except ValueError:
1196 # os.max() throws a ValueError when the collection is empty.
1217 # os.max() throws a ValueError when the collection is empty.
1197 # Same as python's max().
1218 # Same as python's max().
1198 pass
1219 pass
1199 return baseset(datarepr=('<max %r, %r>', subset, os))
1220 return baseset(datarepr=('<max %r, %r>', subset, os))
1200
1221
1201 @predicate('merge()', safe=True)
1222 @predicate('merge()', safe=True)
1202 def merge(repo, subset, x):
1223 def merge(repo, subset, x):
1203 """Changeset is a merge changeset.
1224 """Changeset is a merge changeset.
1204 """
1225 """
1205 # i18n: "merge" is a keyword
1226 # i18n: "merge" is a keyword
1206 getargs(x, 0, 0, _("merge takes no arguments"))
1227 getargs(x, 0, 0, _("merge takes no arguments"))
1207 cl = repo.changelog
1228 cl = repo.changelog
1208 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1229 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
1209 condrepr='<merge>')
1230 condrepr='<merge>')
1210
1231
1211 @predicate('branchpoint()', safe=True)
1232 @predicate('branchpoint()', safe=True)
1212 def branchpoint(repo, subset, x):
1233 def branchpoint(repo, subset, x):
1213 """Changesets with more than one child.
1234 """Changesets with more than one child.
1214 """
1235 """
1215 # i18n: "branchpoint" is a keyword
1236 # i18n: "branchpoint" is a keyword
1216 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1237 getargs(x, 0, 0, _("branchpoint takes no arguments"))
1217 cl = repo.changelog
1238 cl = repo.changelog
1218 if not subset:
1239 if not subset:
1219 return baseset()
1240 return baseset()
1220 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1241 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1221 # (and if it is not, it should.)
1242 # (and if it is not, it should.)
1222 baserev = min(subset)
1243 baserev = min(subset)
1223 parentscount = [0]*(len(repo) - baserev)
1244 parentscount = [0]*(len(repo) - baserev)
1224 for r in cl.revs(start=baserev + 1):
1245 for r in cl.revs(start=baserev + 1):
1225 for p in cl.parentrevs(r):
1246 for p in cl.parentrevs(r):
1226 if p >= baserev:
1247 if p >= baserev:
1227 parentscount[p - baserev] += 1
1248 parentscount[p - baserev] += 1
1228 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1249 return subset.filter(lambda r: parentscount[r - baserev] > 1,
1229 condrepr='<branchpoint>')
1250 condrepr='<branchpoint>')
1230
1251
1231 @predicate('min(set)', safe=True)
1252 @predicate('min(set)', safe=True)
1232 def minrev(repo, subset, x):
1253 def minrev(repo, subset, x):
1233 """Changeset with lowest revision number in set.
1254 """Changeset with lowest revision number in set.
1234 """
1255 """
1235 os = getset(repo, fullreposet(repo), x)
1256 os = getset(repo, fullreposet(repo), x)
1236 try:
1257 try:
1237 m = os.min()
1258 m = os.min()
1238 if m in subset:
1259 if m in subset:
1239 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1260 return baseset([m], datarepr=('<min %r, %r>', subset, os))
1240 except ValueError:
1261 except ValueError:
1241 # os.min() throws a ValueError when the collection is empty.
1262 # os.min() throws a ValueError when the collection is empty.
1242 # Same as python's min().
1263 # Same as python's min().
1243 pass
1264 pass
1244 return baseset(datarepr=('<min %r, %r>', subset, os))
1265 return baseset(datarepr=('<min %r, %r>', subset, os))
1245
1266
1246 @predicate('modifies(pattern)', safe=True)
1267 @predicate('modifies(pattern)', safe=True)
1247 def modifies(repo, subset, x):
1268 def modifies(repo, subset, x):
1248 """Changesets modifying files matched by pattern.
1269 """Changesets modifying files matched by pattern.
1249
1270
1250 The pattern without explicit kind like ``glob:`` is expected to be
1271 The pattern without explicit kind like ``glob:`` is expected to be
1251 relative to the current directory and match against a file or a
1272 relative to the current directory and match against a file or a
1252 directory.
1273 directory.
1253 """
1274 """
1254 # i18n: "modifies" is a keyword
1275 # i18n: "modifies" is a keyword
1255 pat = getstring(x, _("modifies requires a pattern"))
1276 pat = getstring(x, _("modifies requires a pattern"))
1256 return checkstatus(repo, subset, pat, 0)
1277 return checkstatus(repo, subset, pat, 0)
1257
1278
1258 @predicate('named(namespace)')
1279 @predicate('named(namespace)')
1259 def named(repo, subset, x):
1280 def named(repo, subset, x):
1260 """The changesets in a given namespace.
1281 """The changesets in a given namespace.
1261
1282
1262 Pattern matching is supported for `namespace`. See
1283 Pattern matching is supported for `namespace`. See
1263 :hg:`help revisions.patterns`.
1284 :hg:`help revisions.patterns`.
1264 """
1285 """
1265 # i18n: "named" is a keyword
1286 # i18n: "named" is a keyword
1266 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1287 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1267
1288
1268 ns = getstring(args[0],
1289 ns = getstring(args[0],
1269 # i18n: "named" is a keyword
1290 # i18n: "named" is a keyword
1270 _('the argument to named must be a string'))
1291 _('the argument to named must be a string'))
1271 kind, pattern, matcher = util.stringmatcher(ns)
1292 kind, pattern, matcher = util.stringmatcher(ns)
1272 namespaces = set()
1293 namespaces = set()
1273 if kind == 'literal':
1294 if kind == 'literal':
1274 if pattern not in repo.names:
1295 if pattern not in repo.names:
1275 raise error.RepoLookupError(_("namespace '%s' does not exist")
1296 raise error.RepoLookupError(_("namespace '%s' does not exist")
1276 % ns)
1297 % ns)
1277 namespaces.add(repo.names[pattern])
1298 namespaces.add(repo.names[pattern])
1278 else:
1299 else:
1279 for name, ns in repo.names.iteritems():
1300 for name, ns in repo.names.iteritems():
1280 if matcher(name):
1301 if matcher(name):
1281 namespaces.add(ns)
1302 namespaces.add(ns)
1282 if not namespaces:
1303 if not namespaces:
1283 raise error.RepoLookupError(_("no namespace exists"
1304 raise error.RepoLookupError(_("no namespace exists"
1284 " that match '%s'") % pattern)
1305 " that match '%s'") % pattern)
1285
1306
1286 names = set()
1307 names = set()
1287 for ns in namespaces:
1308 for ns in namespaces:
1288 for name in ns.listnames(repo):
1309 for name in ns.listnames(repo):
1289 if name not in ns.deprecated:
1310 if name not in ns.deprecated:
1290 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1311 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1291
1312
1292 names -= {node.nullrev}
1313 names -= {node.nullrev}
1293 return subset & names
1314 return subset & names
1294
1315
1295 @predicate('id(string)', safe=True)
1316 @predicate('id(string)', safe=True)
1296 def node_(repo, subset, x):
1317 def node_(repo, subset, x):
1297 """Revision non-ambiguously specified by the given hex string prefix.
1318 """Revision non-ambiguously specified by the given hex string prefix.
1298 """
1319 """
1299 # i18n: "id" is a keyword
1320 # i18n: "id" is a keyword
1300 l = getargs(x, 1, 1, _("id requires one argument"))
1321 l = getargs(x, 1, 1, _("id requires one argument"))
1301 # i18n: "id" is a keyword
1322 # i18n: "id" is a keyword
1302 n = getstring(l[0], _("id requires a string"))
1323 n = getstring(l[0], _("id requires a string"))
1303 if len(n) == 40:
1324 if len(n) == 40:
1304 try:
1325 try:
1305 rn = repo.changelog.rev(node.bin(n))
1326 rn = repo.changelog.rev(node.bin(n))
1306 except error.WdirUnsupported:
1327 except error.WdirUnsupported:
1307 rn = node.wdirrev
1328 rn = node.wdirrev
1308 except (LookupError, TypeError):
1329 except (LookupError, TypeError):
1309 rn = None
1330 rn = None
1310 else:
1331 else:
1311 rn = None
1332 rn = None
1312 try:
1333 try:
1313 pm = repo.changelog._partialmatch(n)
1334 pm = repo.changelog._partialmatch(n)
1314 if pm is not None:
1335 if pm is not None:
1315 rn = repo.changelog.rev(pm)
1336 rn = repo.changelog.rev(pm)
1316 except error.WdirUnsupported:
1337 except error.WdirUnsupported:
1317 rn = node.wdirrev
1338 rn = node.wdirrev
1318
1339
1319 if rn is None:
1340 if rn is None:
1320 return baseset()
1341 return baseset()
1321 result = baseset([rn])
1342 result = baseset([rn])
1322 return result & subset
1343 return result & subset
1323
1344
1324 @predicate('obsolete()', safe=True)
1345 @predicate('obsolete()', safe=True)
1325 def obsolete(repo, subset, x):
1346 def obsolete(repo, subset, x):
1326 """Mutable changeset with a newer version."""
1347 """Mutable changeset with a newer version."""
1327 # i18n: "obsolete" is a keyword
1348 # i18n: "obsolete" is a keyword
1328 getargs(x, 0, 0, _("obsolete takes no arguments"))
1349 getargs(x, 0, 0, _("obsolete takes no arguments"))
1329 obsoletes = obsmod.getrevs(repo, 'obsolete')
1350 obsoletes = obsmod.getrevs(repo, 'obsolete')
1330 return subset & obsoletes
1351 return subset & obsoletes
1331
1352
1332 @predicate('only(set, [set])', safe=True)
1353 @predicate('only(set, [set])', safe=True)
1333 def only(repo, subset, x):
1354 def only(repo, subset, x):
1334 """Changesets that are ancestors of the first set that are not ancestors
1355 """Changesets that are ancestors of the first set that are not ancestors
1335 of any other head in the repo. If a second set is specified, the result
1356 of any other head in the repo. If a second set is specified, the result
1336 is ancestors of the first set that are not ancestors of the second set
1357 is ancestors of the first set that are not ancestors of the second set
1337 (i.e. ::<set1> - ::<set2>).
1358 (i.e. ::<set1> - ::<set2>).
1338 """
1359 """
1339 cl = repo.changelog
1360 cl = repo.changelog
1340 # i18n: "only" is a keyword
1361 # i18n: "only" is a keyword
1341 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1362 args = getargs(x, 1, 2, _('only takes one or two arguments'))
1342 include = getset(repo, fullreposet(repo), args[0])
1363 include = getset(repo, fullreposet(repo), args[0])
1343 if len(args) == 1:
1364 if len(args) == 1:
1344 if not include:
1365 if not include:
1345 return baseset()
1366 return baseset()
1346
1367
1347 descendants = set(_revdescendants(repo, include, False))
1368 descendants = set(_revdescendants(repo, include, False))
1348 exclude = [rev for rev in cl.headrevs()
1369 exclude = [rev for rev in cl.headrevs()
1349 if not rev in descendants and not rev in include]
1370 if not rev in descendants and not rev in include]
1350 else:
1371 else:
1351 exclude = getset(repo, fullreposet(repo), args[1])
1372 exclude = getset(repo, fullreposet(repo), args[1])
1352
1373
1353 results = set(cl.findmissingrevs(common=exclude, heads=include))
1374 results = set(cl.findmissingrevs(common=exclude, heads=include))
1354 # XXX we should turn this into a baseset instead of a set, smartset may do
1375 # XXX we should turn this into a baseset instead of a set, smartset may do
1355 # some optimizations from the fact this is a baseset.
1376 # some optimizations from the fact this is a baseset.
1356 return subset & results
1377 return subset & results
1357
1378
1358 @predicate('origin([set])', safe=True)
1379 @predicate('origin([set])', safe=True)
1359 def origin(repo, subset, x):
1380 def origin(repo, subset, x):
1360 """
1381 """
1361 Changesets that were specified as a source for the grafts, transplants or
1382 Changesets that were specified as a source for the grafts, transplants or
1362 rebases that created the given revisions. Omitting the optional set is the
1383 rebases that created the given revisions. Omitting the optional set is the
1363 same as passing all(). If a changeset created by these operations is itself
1384 same as passing all(). If a changeset created by these operations is itself
1364 specified as a source for one of these operations, only the source changeset
1385 specified as a source for one of these operations, only the source changeset
1365 for the first operation is selected.
1386 for the first operation is selected.
1366 """
1387 """
1367 if x is not None:
1388 if x is not None:
1368 dests = getset(repo, fullreposet(repo), x)
1389 dests = getset(repo, fullreposet(repo), x)
1369 else:
1390 else:
1370 dests = fullreposet(repo)
1391 dests = fullreposet(repo)
1371
1392
1372 def _firstsrc(rev):
1393 def _firstsrc(rev):
1373 src = _getrevsource(repo, rev)
1394 src = _getrevsource(repo, rev)
1374 if src is None:
1395 if src is None:
1375 return None
1396 return None
1376
1397
1377 while True:
1398 while True:
1378 prev = _getrevsource(repo, src)
1399 prev = _getrevsource(repo, src)
1379
1400
1380 if prev is None:
1401 if prev is None:
1381 return src
1402 return src
1382 src = prev
1403 src = prev
1383
1404
1384 o = {_firstsrc(r) for r in dests}
1405 o = {_firstsrc(r) for r in dests}
1385 o -= {None}
1406 o -= {None}
1386 # XXX we should turn this into a baseset instead of a set, smartset may do
1407 # XXX we should turn this into a baseset instead of a set, smartset may do
1387 # some optimizations from the fact this is a baseset.
1408 # some optimizations from the fact this is a baseset.
1388 return subset & o
1409 return subset & o
1389
1410
1390 @predicate('outgoing([path])', safe=False)
1411 @predicate('outgoing([path])', safe=False)
1391 def outgoing(repo, subset, x):
1412 def outgoing(repo, subset, x):
1392 """Changesets not found in the specified destination repository, or the
1413 """Changesets not found in the specified destination repository, or the
1393 default push location.
1414 default push location.
1394 """
1415 """
1395 # Avoid cycles.
1416 # Avoid cycles.
1396 from . import (
1417 from . import (
1397 discovery,
1418 discovery,
1398 hg,
1419 hg,
1399 )
1420 )
1400 # i18n: "outgoing" is a keyword
1421 # i18n: "outgoing" is a keyword
1401 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1422 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1402 # i18n: "outgoing" is a keyword
1423 # i18n: "outgoing" is a keyword
1403 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1424 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1404 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1425 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
1405 dest, branches = hg.parseurl(dest)
1426 dest, branches = hg.parseurl(dest)
1406 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1427 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1407 if revs:
1428 if revs:
1408 revs = [repo.lookup(rev) for rev in revs]
1429 revs = [repo.lookup(rev) for rev in revs]
1409 other = hg.peer(repo, {}, dest)
1430 other = hg.peer(repo, {}, dest)
1410 repo.ui.pushbuffer()
1431 repo.ui.pushbuffer()
1411 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1432 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1412 repo.ui.popbuffer()
1433 repo.ui.popbuffer()
1413 cl = repo.changelog
1434 cl = repo.changelog
1414 o = {cl.rev(r) for r in outgoing.missing}
1435 o = {cl.rev(r) for r in outgoing.missing}
1415 return subset & o
1436 return subset & o
1416
1437
1417 @predicate('p1([set])', safe=True)
1438 @predicate('p1([set])', safe=True)
1418 def p1(repo, subset, x):
1439 def p1(repo, subset, x):
1419 """First parent of changesets in set, or the working directory.
1440 """First parent of changesets in set, or the working directory.
1420 """
1441 """
1421 if x is None:
1442 if x is None:
1422 p = repo[x].p1().rev()
1443 p = repo[x].p1().rev()
1423 if p >= 0:
1444 if p >= 0:
1424 return subset & baseset([p])
1445 return subset & baseset([p])
1425 return baseset()
1446 return baseset()
1426
1447
1427 ps = set()
1448 ps = set()
1428 cl = repo.changelog
1449 cl = repo.changelog
1429 for r in getset(repo, fullreposet(repo), x):
1450 for r in getset(repo, fullreposet(repo), x):
1430 try:
1451 try:
1431 ps.add(cl.parentrevs(r)[0])
1452 ps.add(cl.parentrevs(r)[0])
1432 except error.WdirUnsupported:
1453 except error.WdirUnsupported:
1433 ps.add(repo[r].parents()[0].rev())
1454 ps.add(repo[r].parents()[0].rev())
1434 ps -= {node.nullrev}
1455 ps -= {node.nullrev}
1435 # XXX we should turn this into a baseset instead of a set, smartset may do
1456 # XXX we should turn this into a baseset instead of a set, smartset may do
1436 # some optimizations from the fact this is a baseset.
1457 # some optimizations from the fact this is a baseset.
1437 return subset & ps
1458 return subset & ps
1438
1459
1439 @predicate('p2([set])', safe=True)
1460 @predicate('p2([set])', safe=True)
1440 def p2(repo, subset, x):
1461 def p2(repo, subset, x):
1441 """Second parent of changesets in set, or the working directory.
1462 """Second parent of changesets in set, or the working directory.
1442 """
1463 """
1443 if x is None:
1464 if x is None:
1444 ps = repo[x].parents()
1465 ps = repo[x].parents()
1445 try:
1466 try:
1446 p = ps[1].rev()
1467 p = ps[1].rev()
1447 if p >= 0:
1468 if p >= 0:
1448 return subset & baseset([p])
1469 return subset & baseset([p])
1449 return baseset()
1470 return baseset()
1450 except IndexError:
1471 except IndexError:
1451 return baseset()
1472 return baseset()
1452
1473
1453 ps = set()
1474 ps = set()
1454 cl = repo.changelog
1475 cl = repo.changelog
1455 for r in getset(repo, fullreposet(repo), x):
1476 for r in getset(repo, fullreposet(repo), x):
1456 try:
1477 try:
1457 ps.add(cl.parentrevs(r)[1])
1478 ps.add(cl.parentrevs(r)[1])
1458 except error.WdirUnsupported:
1479 except error.WdirUnsupported:
1459 parents = repo[r].parents()
1480 parents = repo[r].parents()
1460 if len(parents) == 2:
1481 if len(parents) == 2:
1461 ps.add(parents[1])
1482 ps.add(parents[1])
1462 ps -= {node.nullrev}
1483 ps -= {node.nullrev}
1463 # XXX we should turn this into a baseset instead of a set, smartset may do
1484 # XXX we should turn this into a baseset instead of a set, smartset may do
1464 # some optimizations from the fact this is a baseset.
1485 # some optimizations from the fact this is a baseset.
1465 return subset & ps
1486 return subset & ps
1466
1487
1467 def parentpost(repo, subset, x, order):
1488 def parentpost(repo, subset, x, order):
1468 return p1(repo, subset, x)
1489 return p1(repo, subset, x)
1469
1490
1470 @predicate('parents([set])', safe=True)
1491 @predicate('parents([set])', safe=True)
1471 def parents(repo, subset, x):
1492 def parents(repo, subset, x):
1472 """
1493 """
1473 The set of all parents for all changesets in set, or the working directory.
1494 The set of all parents for all changesets in set, or the working directory.
1474 """
1495 """
1475 if x is None:
1496 if x is None:
1476 ps = set(p.rev() for p in repo[x].parents())
1497 ps = set(p.rev() for p in repo[x].parents())
1477 else:
1498 else:
1478 ps = set()
1499 ps = set()
1479 cl = repo.changelog
1500 cl = repo.changelog
1480 up = ps.update
1501 up = ps.update
1481 parentrevs = cl.parentrevs
1502 parentrevs = cl.parentrevs
1482 for r in getset(repo, fullreposet(repo), x):
1503 for r in getset(repo, fullreposet(repo), x):
1483 try:
1504 try:
1484 up(parentrevs(r))
1505 up(parentrevs(r))
1485 except error.WdirUnsupported:
1506 except error.WdirUnsupported:
1486 up(p.rev() for p in repo[r].parents())
1507 up(p.rev() for p in repo[r].parents())
1487 ps -= {node.nullrev}
1508 ps -= {node.nullrev}
1488 return subset & ps
1509 return subset & ps
1489
1510
1490 def _phase(repo, subset, *targets):
1511 def _phase(repo, subset, *targets):
1491 """helper to select all rev in <targets> phases"""
1512 """helper to select all rev in <targets> phases"""
1492 s = repo._phasecache.getrevset(repo, targets)
1513 s = repo._phasecache.getrevset(repo, targets)
1493 return subset & s
1514 return subset & s
1494
1515
1495 @predicate('draft()', safe=True)
1516 @predicate('draft()', safe=True)
1496 def draft(repo, subset, x):
1517 def draft(repo, subset, x):
1497 """Changeset in draft phase."""
1518 """Changeset in draft phase."""
1498 # i18n: "draft" is a keyword
1519 # i18n: "draft" is a keyword
1499 getargs(x, 0, 0, _("draft takes no arguments"))
1520 getargs(x, 0, 0, _("draft takes no arguments"))
1500 target = phases.draft
1521 target = phases.draft
1501 return _phase(repo, subset, target)
1522 return _phase(repo, subset, target)
1502
1523
1503 @predicate('secret()', safe=True)
1524 @predicate('secret()', safe=True)
1504 def secret(repo, subset, x):
1525 def secret(repo, subset, x):
1505 """Changeset in secret phase."""
1526 """Changeset in secret phase."""
1506 # i18n: "secret" is a keyword
1527 # i18n: "secret" is a keyword
1507 getargs(x, 0, 0, _("secret takes no arguments"))
1528 getargs(x, 0, 0, _("secret takes no arguments"))
1508 target = phases.secret
1529 target = phases.secret
1509 return _phase(repo, subset, target)
1530 return _phase(repo, subset, target)
1510
1531
1511 def parentspec(repo, subset, x, n, order):
1532 def parentspec(repo, subset, x, n, order):
1512 """``set^0``
1533 """``set^0``
1513 The set.
1534 The set.
1514 ``set^1`` (or ``set^``), ``set^2``
1535 ``set^1`` (or ``set^``), ``set^2``
1515 First or second parent, respectively, of all changesets in set.
1536 First or second parent, respectively, of all changesets in set.
1516 """
1537 """
1517 try:
1538 try:
1518 n = int(n[1])
1539 n = int(n[1])
1519 if n not in (0, 1, 2):
1540 if n not in (0, 1, 2):
1520 raise ValueError
1541 raise ValueError
1521 except (TypeError, ValueError):
1542 except (TypeError, ValueError):
1522 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1543 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
1523 ps = set()
1544 ps = set()
1524 cl = repo.changelog
1545 cl = repo.changelog
1525 for r in getset(repo, fullreposet(repo), x):
1546 for r in getset(repo, fullreposet(repo), x):
1526 if n == 0:
1547 if n == 0:
1527 ps.add(r)
1548 ps.add(r)
1528 elif n == 1:
1549 elif n == 1:
1529 try:
1550 try:
1530 ps.add(cl.parentrevs(r)[0])
1551 ps.add(cl.parentrevs(r)[0])
1531 except error.WdirUnsupported:
1552 except error.WdirUnsupported:
1532 ps.add(repo[r].parents()[0].rev())
1553 ps.add(repo[r].parents()[0].rev())
1533 else:
1554 else:
1534 try:
1555 try:
1535 parents = cl.parentrevs(r)
1556 parents = cl.parentrevs(r)
1536 if parents[1] != node.nullrev:
1557 if parents[1] != node.nullrev:
1537 ps.add(parents[1])
1558 ps.add(parents[1])
1538 except error.WdirUnsupported:
1559 except error.WdirUnsupported:
1539 parents = repo[r].parents()
1560 parents = repo[r].parents()
1540 if len(parents) == 2:
1561 if len(parents) == 2:
1541 ps.add(parents[1].rev())
1562 ps.add(parents[1].rev())
1542 return subset & ps
1563 return subset & ps
1543
1564
1544 @predicate('present(set)', safe=True)
1565 @predicate('present(set)', safe=True)
1545 def present(repo, subset, x):
1566 def present(repo, subset, x):
1546 """An empty set, if any revision in set isn't found; otherwise,
1567 """An empty set, if any revision in set isn't found; otherwise,
1547 all revisions in set.
1568 all revisions in set.
1548
1569
1549 If any of specified revisions is not present in the local repository,
1570 If any of specified revisions is not present in the local repository,
1550 the query is normally aborted. But this predicate allows the query
1571 the query is normally aborted. But this predicate allows the query
1551 to continue even in such cases.
1572 to continue even in such cases.
1552 """
1573 """
1553 try:
1574 try:
1554 return getset(repo, subset, x)
1575 return getset(repo, subset, x)
1555 except error.RepoLookupError:
1576 except error.RepoLookupError:
1556 return baseset()
1577 return baseset()
1557
1578
1558 # for internal use
1579 # for internal use
1559 @predicate('_notpublic', safe=True)
1580 @predicate('_notpublic', safe=True)
1560 def _notpublic(repo, subset, x):
1581 def _notpublic(repo, subset, x):
1561 getargs(x, 0, 0, "_notpublic takes no arguments")
1582 getargs(x, 0, 0, "_notpublic takes no arguments")
1562 return _phase(repo, subset, phases.draft, phases.secret)
1583 return _phase(repo, subset, phases.draft, phases.secret)
1563
1584
1564 @predicate('public()', safe=True)
1585 @predicate('public()', safe=True)
1565 def public(repo, subset, x):
1586 def public(repo, subset, x):
1566 """Changeset in public phase."""
1587 """Changeset in public phase."""
1567 # i18n: "public" is a keyword
1588 # i18n: "public" is a keyword
1568 getargs(x, 0, 0, _("public takes no arguments"))
1589 getargs(x, 0, 0, _("public takes no arguments"))
1569 phase = repo._phasecache.phase
1590 phase = repo._phasecache.phase
1570 target = phases.public
1591 target = phases.public
1571 condition = lambda r: phase(repo, r) == target
1592 condition = lambda r: phase(repo, r) == target
1572 return subset.filter(condition, condrepr=('<phase %r>', target),
1593 return subset.filter(condition, condrepr=('<phase %r>', target),
1573 cache=False)
1594 cache=False)
1574
1595
1575 @predicate('remote([id [,path]])', safe=False)
1596 @predicate('remote([id [,path]])', safe=False)
1576 def remote(repo, subset, x):
1597 def remote(repo, subset, x):
1577 """Local revision that corresponds to the given identifier in a
1598 """Local revision that corresponds to the given identifier in a
1578 remote repository, if present. Here, the '.' identifier is a
1599 remote repository, if present. Here, the '.' identifier is a
1579 synonym for the current local branch.
1600 synonym for the current local branch.
1580 """
1601 """
1581
1602
1582 from . import hg # avoid start-up nasties
1603 from . import hg # avoid start-up nasties
1583 # i18n: "remote" is a keyword
1604 # i18n: "remote" is a keyword
1584 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1605 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1585
1606
1586 q = '.'
1607 q = '.'
1587 if len(l) > 0:
1608 if len(l) > 0:
1588 # i18n: "remote" is a keyword
1609 # i18n: "remote" is a keyword
1589 q = getstring(l[0], _("remote requires a string id"))
1610 q = getstring(l[0], _("remote requires a string id"))
1590 if q == '.':
1611 if q == '.':
1591 q = repo['.'].branch()
1612 q = repo['.'].branch()
1592
1613
1593 dest = ''
1614 dest = ''
1594 if len(l) > 1:
1615 if len(l) > 1:
1595 # i18n: "remote" is a keyword
1616 # i18n: "remote" is a keyword
1596 dest = getstring(l[1], _("remote requires a repository path"))
1617 dest = getstring(l[1], _("remote requires a repository path"))
1597 dest = repo.ui.expandpath(dest or 'default')
1618 dest = repo.ui.expandpath(dest or 'default')
1598 dest, branches = hg.parseurl(dest)
1619 dest, branches = hg.parseurl(dest)
1599 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1620 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1600 if revs:
1621 if revs:
1601 revs = [repo.lookup(rev) for rev in revs]
1622 revs = [repo.lookup(rev) for rev in revs]
1602 other = hg.peer(repo, {}, dest)
1623 other = hg.peer(repo, {}, dest)
1603 n = other.lookup(q)
1624 n = other.lookup(q)
1604 if n in repo:
1625 if n in repo:
1605 r = repo[n].rev()
1626 r = repo[n].rev()
1606 if r in subset:
1627 if r in subset:
1607 return baseset([r])
1628 return baseset([r])
1608 return baseset()
1629 return baseset()
1609
1630
1610 @predicate('removes(pattern)', safe=True)
1631 @predicate('removes(pattern)', safe=True)
1611 def removes(repo, subset, x):
1632 def removes(repo, subset, x):
1612 """Changesets which remove files matching pattern.
1633 """Changesets which remove files matching pattern.
1613
1634
1614 The pattern without explicit kind like ``glob:`` is expected to be
1635 The pattern without explicit kind like ``glob:`` is expected to be
1615 relative to the current directory and match against a file or a
1636 relative to the current directory and match against a file or a
1616 directory.
1637 directory.
1617 """
1638 """
1618 # i18n: "removes" is a keyword
1639 # i18n: "removes" is a keyword
1619 pat = getstring(x, _("removes requires a pattern"))
1640 pat = getstring(x, _("removes requires a pattern"))
1620 return checkstatus(repo, subset, pat, 2)
1641 return checkstatus(repo, subset, pat, 2)
1621
1642
1622 @predicate('rev(number)', safe=True)
1643 @predicate('rev(number)', safe=True)
1623 def rev(repo, subset, x):
1644 def rev(repo, subset, x):
1624 """Revision with the given numeric identifier.
1645 """Revision with the given numeric identifier.
1625 """
1646 """
1626 # i18n: "rev" is a keyword
1647 # i18n: "rev" is a keyword
1627 l = getargs(x, 1, 1, _("rev requires one argument"))
1648 l = getargs(x, 1, 1, _("rev requires one argument"))
1628 try:
1649 try:
1629 # i18n: "rev" is a keyword
1650 # i18n: "rev" is a keyword
1630 l = int(getstring(l[0], _("rev requires a number")))
1651 l = int(getstring(l[0], _("rev requires a number")))
1631 except (TypeError, ValueError):
1652 except (TypeError, ValueError):
1632 # i18n: "rev" is a keyword
1653 # i18n: "rev" is a keyword
1633 raise error.ParseError(_("rev expects a number"))
1654 raise error.ParseError(_("rev expects a number"))
1634 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1655 if l not in repo.changelog and l not in (node.nullrev, node.wdirrev):
1635 return baseset()
1656 return baseset()
1636 return subset & baseset([l])
1657 return subset & baseset([l])
1637
1658
1638 @predicate('matching(revision [, field])', safe=True)
1659 @predicate('matching(revision [, field])', safe=True)
1639 def matching(repo, subset, x):
1660 def matching(repo, subset, x):
1640 """Changesets in which a given set of fields match the set of fields in the
1661 """Changesets in which a given set of fields match the set of fields in the
1641 selected revision or set.
1662 selected revision or set.
1642
1663
1643 To match more than one field pass the list of fields to match separated
1664 To match more than one field pass the list of fields to match separated
1644 by spaces (e.g. ``author description``).
1665 by spaces (e.g. ``author description``).
1645
1666
1646 Valid fields are most regular revision fields and some special fields.
1667 Valid fields are most regular revision fields and some special fields.
1647
1668
1648 Regular revision fields are ``description``, ``author``, ``branch``,
1669 Regular revision fields are ``description``, ``author``, ``branch``,
1649 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1670 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
1650 and ``diff``.
1671 and ``diff``.
1651 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1672 Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
1652 contents of the revision. Two revisions matching their ``diff`` will
1673 contents of the revision. Two revisions matching their ``diff`` will
1653 also match their ``files``.
1674 also match their ``files``.
1654
1675
1655 Special fields are ``summary`` and ``metadata``:
1676 Special fields are ``summary`` and ``metadata``:
1656 ``summary`` matches the first line of the description.
1677 ``summary`` matches the first line of the description.
1657 ``metadata`` is equivalent to matching ``description user date``
1678 ``metadata`` is equivalent to matching ``description user date``
1658 (i.e. it matches the main metadata fields).
1679 (i.e. it matches the main metadata fields).
1659
1680
1660 ``metadata`` is the default field which is used when no fields are
1681 ``metadata`` is the default field which is used when no fields are
1661 specified. You can match more than one field at a time.
1682 specified. You can match more than one field at a time.
1662 """
1683 """
1663 # i18n: "matching" is a keyword
1684 # i18n: "matching" is a keyword
1664 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1685 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
1665
1686
1666 revs = getset(repo, fullreposet(repo), l[0])
1687 revs = getset(repo, fullreposet(repo), l[0])
1667
1688
1668 fieldlist = ['metadata']
1689 fieldlist = ['metadata']
1669 if len(l) > 1:
1690 if len(l) > 1:
1670 fieldlist = getstring(l[1],
1691 fieldlist = getstring(l[1],
1671 # i18n: "matching" is a keyword
1692 # i18n: "matching" is a keyword
1672 _("matching requires a string "
1693 _("matching requires a string "
1673 "as its second argument")).split()
1694 "as its second argument")).split()
1674
1695
1675 # Make sure that there are no repeated fields,
1696 # Make sure that there are no repeated fields,
1676 # expand the 'special' 'metadata' field type
1697 # expand the 'special' 'metadata' field type
1677 # and check the 'files' whenever we check the 'diff'
1698 # and check the 'files' whenever we check the 'diff'
1678 fields = []
1699 fields = []
1679 for field in fieldlist:
1700 for field in fieldlist:
1680 if field == 'metadata':
1701 if field == 'metadata':
1681 fields += ['user', 'description', 'date']
1702 fields += ['user', 'description', 'date']
1682 elif field == 'diff':
1703 elif field == 'diff':
1683 # a revision matching the diff must also match the files
1704 # a revision matching the diff must also match the files
1684 # since matching the diff is very costly, make sure to
1705 # since matching the diff is very costly, make sure to
1685 # also match the files first
1706 # also match the files first
1686 fields += ['files', 'diff']
1707 fields += ['files', 'diff']
1687 else:
1708 else:
1688 if field == 'author':
1709 if field == 'author':
1689 field = 'user'
1710 field = 'user'
1690 fields.append(field)
1711 fields.append(field)
1691 fields = set(fields)
1712 fields = set(fields)
1692 if 'summary' in fields and 'description' in fields:
1713 if 'summary' in fields and 'description' in fields:
1693 # If a revision matches its description it also matches its summary
1714 # If a revision matches its description it also matches its summary
1694 fields.discard('summary')
1715 fields.discard('summary')
1695
1716
1696 # We may want to match more than one field
1717 # We may want to match more than one field
1697 # Not all fields take the same amount of time to be matched
1718 # Not all fields take the same amount of time to be matched
1698 # Sort the selected fields in order of increasing matching cost
1719 # Sort the selected fields in order of increasing matching cost
1699 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1720 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
1700 'files', 'description', 'substate', 'diff']
1721 'files', 'description', 'substate', 'diff']
1701 def fieldkeyfunc(f):
1722 def fieldkeyfunc(f):
1702 try:
1723 try:
1703 return fieldorder.index(f)
1724 return fieldorder.index(f)
1704 except ValueError:
1725 except ValueError:
1705 # assume an unknown field is very costly
1726 # assume an unknown field is very costly
1706 return len(fieldorder)
1727 return len(fieldorder)
1707 fields = list(fields)
1728 fields = list(fields)
1708 fields.sort(key=fieldkeyfunc)
1729 fields.sort(key=fieldkeyfunc)
1709
1730
1710 # Each field will be matched with its own "getfield" function
1731 # Each field will be matched with its own "getfield" function
1711 # which will be added to the getfieldfuncs array of functions
1732 # which will be added to the getfieldfuncs array of functions
1712 getfieldfuncs = []
1733 getfieldfuncs = []
1713 _funcs = {
1734 _funcs = {
1714 'user': lambda r: repo[r].user(),
1735 'user': lambda r: repo[r].user(),
1715 'branch': lambda r: repo[r].branch(),
1736 'branch': lambda r: repo[r].branch(),
1716 'date': lambda r: repo[r].date(),
1737 'date': lambda r: repo[r].date(),
1717 'description': lambda r: repo[r].description(),
1738 'description': lambda r: repo[r].description(),
1718 'files': lambda r: repo[r].files(),
1739 'files': lambda r: repo[r].files(),
1719 'parents': lambda r: repo[r].parents(),
1740 'parents': lambda r: repo[r].parents(),
1720 'phase': lambda r: repo[r].phase(),
1741 'phase': lambda r: repo[r].phase(),
1721 'substate': lambda r: repo[r].substate,
1742 'substate': lambda r: repo[r].substate,
1722 'summary': lambda r: repo[r].description().splitlines()[0],
1743 'summary': lambda r: repo[r].description().splitlines()[0],
1723 'diff': lambda r: list(repo[r].diff(git=True),)
1744 'diff': lambda r: list(repo[r].diff(git=True),)
1724 }
1745 }
1725 for info in fields:
1746 for info in fields:
1726 getfield = _funcs.get(info, None)
1747 getfield = _funcs.get(info, None)
1727 if getfield is None:
1748 if getfield is None:
1728 raise error.ParseError(
1749 raise error.ParseError(
1729 # i18n: "matching" is a keyword
1750 # i18n: "matching" is a keyword
1730 _("unexpected field name passed to matching: %s") % info)
1751 _("unexpected field name passed to matching: %s") % info)
1731 getfieldfuncs.append(getfield)
1752 getfieldfuncs.append(getfield)
1732 # convert the getfield array of functions into a "getinfo" function
1753 # convert the getfield array of functions into a "getinfo" function
1733 # which returns an array of field values (or a single value if there
1754 # which returns an array of field values (or a single value if there
1734 # is only one field to match)
1755 # is only one field to match)
1735 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1756 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1736
1757
1737 def matches(x):
1758 def matches(x):
1738 for rev in revs:
1759 for rev in revs:
1739 target = getinfo(rev)
1760 target = getinfo(rev)
1740 match = True
1761 match = True
1741 for n, f in enumerate(getfieldfuncs):
1762 for n, f in enumerate(getfieldfuncs):
1742 if target[n] != f(x):
1763 if target[n] != f(x):
1743 match = False
1764 match = False
1744 if match:
1765 if match:
1745 return True
1766 return True
1746 return False
1767 return False
1747
1768
1748 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1769 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1749
1770
1750 @predicate('reverse(set)', safe=True, takeorder=True)
1771 @predicate('reverse(set)', safe=True, takeorder=True)
1751 def reverse(repo, subset, x, order):
1772 def reverse(repo, subset, x, order):
1752 """Reverse order of set.
1773 """Reverse order of set.
1753 """
1774 """
1754 l = getset(repo, subset, x)
1775 l = getset(repo, subset, x)
1755 if order == defineorder:
1776 if order == defineorder:
1756 l.reverse()
1777 l.reverse()
1757 return l
1778 return l
1758
1779
1759 @predicate('roots(set)', safe=True)
1780 @predicate('roots(set)', safe=True)
1760 def roots(repo, subset, x):
1781 def roots(repo, subset, x):
1761 """Changesets in set with no parent changeset in set.
1782 """Changesets in set with no parent changeset in set.
1762 """
1783 """
1763 s = getset(repo, fullreposet(repo), x)
1784 s = getset(repo, fullreposet(repo), x)
1764 parents = repo.changelog.parentrevs
1785 parents = repo.changelog.parentrevs
1765 def filter(r):
1786 def filter(r):
1766 for p in parents(r):
1787 for p in parents(r):
1767 if 0 <= p and p in s:
1788 if 0 <= p and p in s:
1768 return False
1789 return False
1769 return True
1790 return True
1770 return subset & s.filter(filter, condrepr='<roots>')
1791 return subset & s.filter(filter, condrepr='<roots>')
1771
1792
1772 _sortkeyfuncs = {
1793 _sortkeyfuncs = {
1773 'rev': lambda c: c.rev(),
1794 'rev': lambda c: c.rev(),
1774 'branch': lambda c: c.branch(),
1795 'branch': lambda c: c.branch(),
1775 'desc': lambda c: c.description(),
1796 'desc': lambda c: c.description(),
1776 'user': lambda c: c.user(),
1797 'user': lambda c: c.user(),
1777 'author': lambda c: c.user(),
1798 'author': lambda c: c.user(),
1778 'date': lambda c: c.date()[0],
1799 'date': lambda c: c.date()[0],
1779 }
1800 }
1780
1801
1781 def _getsortargs(x):
1802 def _getsortargs(x):
1782 """Parse sort options into (set, [(key, reverse)], opts)"""
1803 """Parse sort options into (set, [(key, reverse)], opts)"""
1783 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1804 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
1784 if 'set' not in args:
1805 if 'set' not in args:
1785 # i18n: "sort" is a keyword
1806 # i18n: "sort" is a keyword
1786 raise error.ParseError(_('sort requires one or two arguments'))
1807 raise error.ParseError(_('sort requires one or two arguments'))
1787 keys = "rev"
1808 keys = "rev"
1788 if 'keys' in args:
1809 if 'keys' in args:
1789 # i18n: "sort" is a keyword
1810 # i18n: "sort" is a keyword
1790 keys = getstring(args['keys'], _("sort spec must be a string"))
1811 keys = getstring(args['keys'], _("sort spec must be a string"))
1791
1812
1792 keyflags = []
1813 keyflags = []
1793 for k in keys.split():
1814 for k in keys.split():
1794 fk = k
1815 fk = k
1795 reverse = (k[0] == '-')
1816 reverse = (k[0] == '-')
1796 if reverse:
1817 if reverse:
1797 k = k[1:]
1818 k = k[1:]
1798 if k not in _sortkeyfuncs and k != 'topo':
1819 if k not in _sortkeyfuncs and k != 'topo':
1799 raise error.ParseError(_("unknown sort key %r") % fk)
1820 raise error.ParseError(_("unknown sort key %r") % fk)
1800 keyflags.append((k, reverse))
1821 keyflags.append((k, reverse))
1801
1822
1802 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1823 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
1803 # i18n: "topo" is a keyword
1824 # i18n: "topo" is a keyword
1804 raise error.ParseError(_('topo sort order cannot be combined '
1825 raise error.ParseError(_('topo sort order cannot be combined '
1805 'with other sort keys'))
1826 'with other sort keys'))
1806
1827
1807 opts = {}
1828 opts = {}
1808 if 'topo.firstbranch' in args:
1829 if 'topo.firstbranch' in args:
1809 if any(k == 'topo' for k, reverse in keyflags):
1830 if any(k == 'topo' for k, reverse in keyflags):
1810 opts['topo.firstbranch'] = args['topo.firstbranch']
1831 opts['topo.firstbranch'] = args['topo.firstbranch']
1811 else:
1832 else:
1812 # i18n: "topo" and "topo.firstbranch" are keywords
1833 # i18n: "topo" and "topo.firstbranch" are keywords
1813 raise error.ParseError(_('topo.firstbranch can only be used '
1834 raise error.ParseError(_('topo.firstbranch can only be used '
1814 'when using the topo sort key'))
1835 'when using the topo sort key'))
1815
1836
1816 return args['set'], keyflags, opts
1837 return args['set'], keyflags, opts
1817
1838
1818 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1839 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
1819 def sort(repo, subset, x, order):
1840 def sort(repo, subset, x, order):
1820 """Sort set by keys. The default sort order is ascending, specify a key
1841 """Sort set by keys. The default sort order is ascending, specify a key
1821 as ``-key`` to sort in descending order.
1842 as ``-key`` to sort in descending order.
1822
1843
1823 The keys can be:
1844 The keys can be:
1824
1845
1825 - ``rev`` for the revision number,
1846 - ``rev`` for the revision number,
1826 - ``branch`` for the branch name,
1847 - ``branch`` for the branch name,
1827 - ``desc`` for the commit message (description),
1848 - ``desc`` for the commit message (description),
1828 - ``user`` for user name (``author`` can be used as an alias),
1849 - ``user`` for user name (``author`` can be used as an alias),
1829 - ``date`` for the commit date
1850 - ``date`` for the commit date
1830 - ``topo`` for a reverse topographical sort
1851 - ``topo`` for a reverse topographical sort
1831
1852
1832 The ``topo`` sort order cannot be combined with other sort keys. This sort
1853 The ``topo`` sort order cannot be combined with other sort keys. This sort
1833 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1854 takes one optional argument, ``topo.firstbranch``, which takes a revset that
1834 specifies what topographical branches to prioritize in the sort.
1855 specifies what topographical branches to prioritize in the sort.
1835
1856
1836 """
1857 """
1837 s, keyflags, opts = _getsortargs(x)
1858 s, keyflags, opts = _getsortargs(x)
1838 revs = getset(repo, subset, s)
1859 revs = getset(repo, subset, s)
1839
1860
1840 if not keyflags or order != defineorder:
1861 if not keyflags or order != defineorder:
1841 return revs
1862 return revs
1842 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1863 if len(keyflags) == 1 and keyflags[0][0] == "rev":
1843 revs.sort(reverse=keyflags[0][1])
1864 revs.sort(reverse=keyflags[0][1])
1844 return revs
1865 return revs
1845 elif keyflags[0][0] == "topo":
1866 elif keyflags[0][0] == "topo":
1846 firstbranch = ()
1867 firstbranch = ()
1847 if 'topo.firstbranch' in opts:
1868 if 'topo.firstbranch' in opts:
1848 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1869 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
1849 revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
1870 revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
1850 istopo=True)
1871 istopo=True)
1851 if keyflags[0][1]:
1872 if keyflags[0][1]:
1852 revs.reverse()
1873 revs.reverse()
1853 return revs
1874 return revs
1854
1875
1855 # sort() is guaranteed to be stable
1876 # sort() is guaranteed to be stable
1856 ctxs = [repo[r] for r in revs]
1877 ctxs = [repo[r] for r in revs]
1857 for k, reverse in reversed(keyflags):
1878 for k, reverse in reversed(keyflags):
1858 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1879 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
1859 return baseset([c.rev() for c in ctxs])
1880 return baseset([c.rev() for c in ctxs])
1860
1881
1861 def _toposort(revs, parentsfunc, firstbranch=()):
1882 def _toposort(revs, parentsfunc, firstbranch=()):
1862 """Yield revisions from heads to roots one (topo) branch at a time.
1883 """Yield revisions from heads to roots one (topo) branch at a time.
1863
1884
1864 This function aims to be used by a graph generator that wishes to minimize
1885 This function aims to be used by a graph generator that wishes to minimize
1865 the number of parallel branches and their interleaving.
1886 the number of parallel branches and their interleaving.
1866
1887
1867 Example iteration order (numbers show the "true" order in a changelog):
1888 Example iteration order (numbers show the "true" order in a changelog):
1868
1889
1869 o 4
1890 o 4
1870 |
1891 |
1871 o 1
1892 o 1
1872 |
1893 |
1873 | o 3
1894 | o 3
1874 | |
1895 | |
1875 | o 2
1896 | o 2
1876 |/
1897 |/
1877 o 0
1898 o 0
1878
1899
1879 Note that the ancestors of merges are understood by the current
1900 Note that the ancestors of merges are understood by the current
1880 algorithm to be on the same branch. This means no reordering will
1901 algorithm to be on the same branch. This means no reordering will
1881 occur behind a merge.
1902 occur behind a merge.
1882 """
1903 """
1883
1904
1884 ### Quick summary of the algorithm
1905 ### Quick summary of the algorithm
1885 #
1906 #
1886 # This function is based around a "retention" principle. We keep revisions
1907 # This function is based around a "retention" principle. We keep revisions
1887 # in memory until we are ready to emit a whole branch that immediately
1908 # in memory until we are ready to emit a whole branch that immediately
1888 # "merges" into an existing one. This reduces the number of parallel
1909 # "merges" into an existing one. This reduces the number of parallel
1889 # branches with interleaved revisions.
1910 # branches with interleaved revisions.
1890 #
1911 #
1891 # During iteration revs are split into two groups:
1912 # During iteration revs are split into two groups:
1892 # A) revision already emitted
1913 # A) revision already emitted
1893 # B) revision in "retention". They are stored as different subgroups.
1914 # B) revision in "retention". They are stored as different subgroups.
1894 #
1915 #
1895 # for each REV, we do the following logic:
1916 # for each REV, we do the following logic:
1896 #
1917 #
1897 # 1) if REV is a parent of (A), we will emit it. If there is a
1918 # 1) if REV is a parent of (A), we will emit it. If there is a
1898 # retention group ((B) above) that is blocked on REV being
1919 # retention group ((B) above) that is blocked on REV being
1899 # available, we emit all the revisions out of that retention
1920 # available, we emit all the revisions out of that retention
1900 # group first.
1921 # group first.
1901 #
1922 #
1902 # 2) else, we'll search for a subgroup in (B) awaiting for REV to be
1923 # 2) else, we'll search for a subgroup in (B) awaiting for REV to be
1903 # available, if such subgroup exist, we add REV to it and the subgroup is
1924 # available, if such subgroup exist, we add REV to it and the subgroup is
1904 # now awaiting for REV.parents() to be available.
1925 # now awaiting for REV.parents() to be available.
1905 #
1926 #
1906 # 3) finally if no such group existed in (B), we create a new subgroup.
1927 # 3) finally if no such group existed in (B), we create a new subgroup.
1907 #
1928 #
1908 #
1929 #
1909 # To bootstrap the algorithm, we emit the tipmost revision (which
1930 # To bootstrap the algorithm, we emit the tipmost revision (which
1910 # puts it in group (A) from above).
1931 # puts it in group (A) from above).
1911
1932
1912 revs.sort(reverse=True)
1933 revs.sort(reverse=True)
1913
1934
1914 # Set of parents of revision that have been emitted. They can be considered
1935 # Set of parents of revision that have been emitted. They can be considered
1915 # unblocked as the graph generator is already aware of them so there is no
1936 # unblocked as the graph generator is already aware of them so there is no
1916 # need to delay the revisions that reference them.
1937 # need to delay the revisions that reference them.
1917 #
1938 #
1918 # If someone wants to prioritize a branch over the others, pre-filling this
1939 # If someone wants to prioritize a branch over the others, pre-filling this
1919 # set will force all other branches to wait until this branch is ready to be
1940 # set will force all other branches to wait until this branch is ready to be
1920 # emitted.
1941 # emitted.
1921 unblocked = set(firstbranch)
1942 unblocked = set(firstbranch)
1922
1943
1923 # list of groups waiting to be displayed, each group is defined by:
1944 # list of groups waiting to be displayed, each group is defined by:
1924 #
1945 #
1925 # (revs: lists of revs waiting to be displayed,
1946 # (revs: lists of revs waiting to be displayed,
1926 # blocked: set of that cannot be displayed before those in 'revs')
1947 # blocked: set of that cannot be displayed before those in 'revs')
1927 #
1948 #
1928 # The second value ('blocked') correspond to parents of any revision in the
1949 # The second value ('blocked') correspond to parents of any revision in the
1929 # group ('revs') that is not itself contained in the group. The main idea
1950 # group ('revs') that is not itself contained in the group. The main idea
1930 # of this algorithm is to delay as much as possible the emission of any
1951 # of this algorithm is to delay as much as possible the emission of any
1931 # revision. This means waiting for the moment we are about to display
1952 # revision. This means waiting for the moment we are about to display
1932 # these parents to display the revs in a group.
1953 # these parents to display the revs in a group.
1933 #
1954 #
1934 # This first implementation is smart until it encounters a merge: it will
1955 # This first implementation is smart until it encounters a merge: it will
1935 # emit revs as soon as any parent is about to be emitted and can grow an
1956 # emit revs as soon as any parent is about to be emitted and can grow an
1936 # arbitrary number of revs in 'blocked'. In practice this mean we properly
1957 # arbitrary number of revs in 'blocked'. In practice this mean we properly
1937 # retains new branches but gives up on any special ordering for ancestors
1958 # retains new branches but gives up on any special ordering for ancestors
1938 # of merges. The implementation can be improved to handle this better.
1959 # of merges. The implementation can be improved to handle this better.
1939 #
1960 #
1940 # The first subgroup is special. It corresponds to all the revision that
1961 # The first subgroup is special. It corresponds to all the revision that
1941 # were already emitted. The 'revs' lists is expected to be empty and the
1962 # were already emitted. The 'revs' lists is expected to be empty and the
1942 # 'blocked' set contains the parents revisions of already emitted revision.
1963 # 'blocked' set contains the parents revisions of already emitted revision.
1943 #
1964 #
1944 # You could pre-seed the <parents> set of groups[0] to a specific
1965 # You could pre-seed the <parents> set of groups[0] to a specific
1945 # changesets to select what the first emitted branch should be.
1966 # changesets to select what the first emitted branch should be.
1946 groups = [([], unblocked)]
1967 groups = [([], unblocked)]
1947 pendingheap = []
1968 pendingheap = []
1948 pendingset = set()
1969 pendingset = set()
1949
1970
1950 heapq.heapify(pendingheap)
1971 heapq.heapify(pendingheap)
1951 heappop = heapq.heappop
1972 heappop = heapq.heappop
1952 heappush = heapq.heappush
1973 heappush = heapq.heappush
1953 for currentrev in revs:
1974 for currentrev in revs:
1954 # Heap works with smallest element, we want highest so we invert
1975 # Heap works with smallest element, we want highest so we invert
1955 if currentrev not in pendingset:
1976 if currentrev not in pendingset:
1956 heappush(pendingheap, -currentrev)
1977 heappush(pendingheap, -currentrev)
1957 pendingset.add(currentrev)
1978 pendingset.add(currentrev)
1958 # iterates on pending rev until after the current rev have been
1979 # iterates on pending rev until after the current rev have been
1959 # processed.
1980 # processed.
1960 rev = None
1981 rev = None
1961 while rev != currentrev:
1982 while rev != currentrev:
1962 rev = -heappop(pendingheap)
1983 rev = -heappop(pendingheap)
1963 pendingset.remove(rev)
1984 pendingset.remove(rev)
1964
1985
1965 # Seek for a subgroup blocked, waiting for the current revision.
1986 # Seek for a subgroup blocked, waiting for the current revision.
1966 matching = [i for i, g in enumerate(groups) if rev in g[1]]
1987 matching = [i for i, g in enumerate(groups) if rev in g[1]]
1967
1988
1968 if matching:
1989 if matching:
1969 # The main idea is to gather together all sets that are blocked
1990 # The main idea is to gather together all sets that are blocked
1970 # on the same revision.
1991 # on the same revision.
1971 #
1992 #
1972 # Groups are merged when a common blocking ancestor is
1993 # Groups are merged when a common blocking ancestor is
1973 # observed. For example, given two groups:
1994 # observed. For example, given two groups:
1974 #
1995 #
1975 # revs [5, 4] waiting for 1
1996 # revs [5, 4] waiting for 1
1976 # revs [3, 2] waiting for 1
1997 # revs [3, 2] waiting for 1
1977 #
1998 #
1978 # These two groups will be merged when we process
1999 # These two groups will be merged when we process
1979 # 1. In theory, we could have merged the groups when
2000 # 1. In theory, we could have merged the groups when
1980 # we added 2 to the group it is now in (we could have
2001 # we added 2 to the group it is now in (we could have
1981 # noticed the groups were both blocked on 1 then), but
2002 # noticed the groups were both blocked on 1 then), but
1982 # the way it works now makes the algorithm simpler.
2003 # the way it works now makes the algorithm simpler.
1983 #
2004 #
1984 # We also always keep the oldest subgroup first. We can
2005 # We also always keep the oldest subgroup first. We can
1985 # probably improve the behavior by having the longest set
2006 # probably improve the behavior by having the longest set
1986 # first. That way, graph algorithms could minimise the length
2007 # first. That way, graph algorithms could minimise the length
1987 # of parallel lines their drawing. This is currently not done.
2008 # of parallel lines their drawing. This is currently not done.
1988 targetidx = matching.pop(0)
2009 targetidx = matching.pop(0)
1989 trevs, tparents = groups[targetidx]
2010 trevs, tparents = groups[targetidx]
1990 for i in matching:
2011 for i in matching:
1991 gr = groups[i]
2012 gr = groups[i]
1992 trevs.extend(gr[0])
2013 trevs.extend(gr[0])
1993 tparents |= gr[1]
2014 tparents |= gr[1]
1994 # delete all merged subgroups (except the one we kept)
2015 # delete all merged subgroups (except the one we kept)
1995 # (starting from the last subgroup for performance and
2016 # (starting from the last subgroup for performance and
1996 # sanity reasons)
2017 # sanity reasons)
1997 for i in reversed(matching):
2018 for i in reversed(matching):
1998 del groups[i]
2019 del groups[i]
1999 else:
2020 else:
2000 # This is a new head. We create a new subgroup for it.
2021 # This is a new head. We create a new subgroup for it.
2001 targetidx = len(groups)
2022 targetidx = len(groups)
2002 groups.append(([], {rev}))
2023 groups.append(([], {rev}))
2003
2024
2004 gr = groups[targetidx]
2025 gr = groups[targetidx]
2005
2026
2006 # We now add the current nodes to this subgroups. This is done
2027 # We now add the current nodes to this subgroups. This is done
2007 # after the subgroup merging because all elements from a subgroup
2028 # after the subgroup merging because all elements from a subgroup
2008 # that relied on this rev must precede it.
2029 # that relied on this rev must precede it.
2009 #
2030 #
2010 # we also update the <parents> set to include the parents of the
2031 # we also update the <parents> set to include the parents of the
2011 # new nodes.
2032 # new nodes.
2012 if rev == currentrev: # only display stuff in rev
2033 if rev == currentrev: # only display stuff in rev
2013 gr[0].append(rev)
2034 gr[0].append(rev)
2014 gr[1].remove(rev)
2035 gr[1].remove(rev)
2015 parents = [p for p in parentsfunc(rev) if p > node.nullrev]
2036 parents = [p for p in parentsfunc(rev) if p > node.nullrev]
2016 gr[1].update(parents)
2037 gr[1].update(parents)
2017 for p in parents:
2038 for p in parents:
2018 if p not in pendingset:
2039 if p not in pendingset:
2019 pendingset.add(p)
2040 pendingset.add(p)
2020 heappush(pendingheap, -p)
2041 heappush(pendingheap, -p)
2021
2042
2022 # Look for a subgroup to display
2043 # Look for a subgroup to display
2023 #
2044 #
2024 # When unblocked is empty (if clause), we were not waiting for any
2045 # When unblocked is empty (if clause), we were not waiting for any
2025 # revisions during the first iteration (if no priority was given) or
2046 # revisions during the first iteration (if no priority was given) or
2026 # if we emitted a whole disconnected set of the graph (reached a
2047 # if we emitted a whole disconnected set of the graph (reached a
2027 # root). In that case we arbitrarily take the oldest known
2048 # root). In that case we arbitrarily take the oldest known
2028 # subgroup. The heuristic could probably be better.
2049 # subgroup. The heuristic could probably be better.
2029 #
2050 #
2030 # Otherwise (elif clause) if the subgroup is blocked on
2051 # Otherwise (elif clause) if the subgroup is blocked on
2031 # a revision we just emitted, we can safely emit it as
2052 # a revision we just emitted, we can safely emit it as
2032 # well.
2053 # well.
2033 if not unblocked:
2054 if not unblocked:
2034 if len(groups) > 1: # display other subset
2055 if len(groups) > 1: # display other subset
2035 targetidx = 1
2056 targetidx = 1
2036 gr = groups[1]
2057 gr = groups[1]
2037 elif not gr[1] & unblocked:
2058 elif not gr[1] & unblocked:
2038 gr = None
2059 gr = None
2039
2060
2040 if gr is not None:
2061 if gr is not None:
2041 # update the set of awaited revisions with the one from the
2062 # update the set of awaited revisions with the one from the
2042 # subgroup
2063 # subgroup
2043 unblocked |= gr[1]
2064 unblocked |= gr[1]
2044 # output all revisions in the subgroup
2065 # output all revisions in the subgroup
2045 for r in gr[0]:
2066 for r in gr[0]:
2046 yield r
2067 yield r
2047 # delete the subgroup that you just output
2068 # delete the subgroup that you just output
2048 # unless it is groups[0] in which case you just empty it.
2069 # unless it is groups[0] in which case you just empty it.
2049 if targetidx:
2070 if targetidx:
2050 del groups[targetidx]
2071 del groups[targetidx]
2051 else:
2072 else:
2052 gr[0][:] = []
2073 gr[0][:] = []
2053 # Check if we have some subgroup waiting for revisions we are not going to
2074 # Check if we have some subgroup waiting for revisions we are not going to
2054 # iterate over
2075 # iterate over
2055 for g in groups:
2076 for g in groups:
2056 for r in g[0]:
2077 for r in g[0]:
2057 yield r
2078 yield r
2058
2079
2059 @predicate('subrepo([pattern])')
2080 @predicate('subrepo([pattern])')
2060 def subrepo(repo, subset, x):
2081 def subrepo(repo, subset, x):
2061 """Changesets that add, modify or remove the given subrepo. If no subrepo
2082 """Changesets that add, modify or remove the given subrepo. If no subrepo
2062 pattern is named, any subrepo changes are returned.
2083 pattern is named, any subrepo changes are returned.
2063 """
2084 """
2064 # i18n: "subrepo" is a keyword
2085 # i18n: "subrepo" is a keyword
2065 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
2086 args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
2066 pat = None
2087 pat = None
2067 if len(args) != 0:
2088 if len(args) != 0:
2068 pat = getstring(args[0], _("subrepo requires a pattern"))
2089 pat = getstring(args[0], _("subrepo requires a pattern"))
2069
2090
2070 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
2091 m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
2071
2092
2072 def submatches(names):
2093 def submatches(names):
2073 k, p, m = util.stringmatcher(pat)
2094 k, p, m = util.stringmatcher(pat)
2074 for name in names:
2095 for name in names:
2075 if m(name):
2096 if m(name):
2076 yield name
2097 yield name
2077
2098
2078 def matches(x):
2099 def matches(x):
2079 c = repo[x]
2100 c = repo[x]
2080 s = repo.status(c.p1().node(), c.node(), match=m)
2101 s = repo.status(c.p1().node(), c.node(), match=m)
2081
2102
2082 if pat is None:
2103 if pat is None:
2083 return s.added or s.modified or s.removed
2104 return s.added or s.modified or s.removed
2084
2105
2085 if s.added:
2106 if s.added:
2086 return any(submatches(c.substate.keys()))
2107 return any(submatches(c.substate.keys()))
2087
2108
2088 if s.modified:
2109 if s.modified:
2089 subs = set(c.p1().substate.keys())
2110 subs = set(c.p1().substate.keys())
2090 subs.update(c.substate.keys())
2111 subs.update(c.substate.keys())
2091
2112
2092 for path in submatches(subs):
2113 for path in submatches(subs):
2093 if c.p1().substate.get(path) != c.substate.get(path):
2114 if c.p1().substate.get(path) != c.substate.get(path):
2094 return True
2115 return True
2095
2116
2096 if s.removed:
2117 if s.removed:
2097 return any(submatches(c.p1().substate.keys()))
2118 return any(submatches(c.p1().substate.keys()))
2098
2119
2099 return False
2120 return False
2100
2121
2101 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
2122 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
2102
2123
2103 def _substringmatcher(pattern, casesensitive=True):
2124 def _substringmatcher(pattern, casesensitive=True):
2104 kind, pattern, matcher = util.stringmatcher(pattern,
2125 kind, pattern, matcher = util.stringmatcher(pattern,
2105 casesensitive=casesensitive)
2126 casesensitive=casesensitive)
2106 if kind == 'literal':
2127 if kind == 'literal':
2107 if not casesensitive:
2128 if not casesensitive:
2108 pattern = encoding.lower(pattern)
2129 pattern = encoding.lower(pattern)
2109 matcher = lambda s: pattern in encoding.lower(s)
2130 matcher = lambda s: pattern in encoding.lower(s)
2110 else:
2131 else:
2111 matcher = lambda s: pattern in s
2132 matcher = lambda s: pattern in s
2112 return kind, pattern, matcher
2133 return kind, pattern, matcher
2113
2134
2114 @predicate('tag([name])', safe=True)
2135 @predicate('tag([name])', safe=True)
2115 def tag(repo, subset, x):
2136 def tag(repo, subset, x):
2116 """The specified tag by name, or all tagged revisions if no name is given.
2137 """The specified tag by name, or all tagged revisions if no name is given.
2117
2138
2118 Pattern matching is supported for `name`. See
2139 Pattern matching is supported for `name`. See
2119 :hg:`help revisions.patterns`.
2140 :hg:`help revisions.patterns`.
2120 """
2141 """
2121 # i18n: "tag" is a keyword
2142 # i18n: "tag" is a keyword
2122 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
2143 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
2123 cl = repo.changelog
2144 cl = repo.changelog
2124 if args:
2145 if args:
2125 pattern = getstring(args[0],
2146 pattern = getstring(args[0],
2126 # i18n: "tag" is a keyword
2147 # i18n: "tag" is a keyword
2127 _('the argument to tag must be a string'))
2148 _('the argument to tag must be a string'))
2128 kind, pattern, matcher = util.stringmatcher(pattern)
2149 kind, pattern, matcher = util.stringmatcher(pattern)
2129 if kind == 'literal':
2150 if kind == 'literal':
2130 # avoid resolving all tags
2151 # avoid resolving all tags
2131 tn = repo._tagscache.tags.get(pattern, None)
2152 tn = repo._tagscache.tags.get(pattern, None)
2132 if tn is None:
2153 if tn is None:
2133 raise error.RepoLookupError(_("tag '%s' does not exist")
2154 raise error.RepoLookupError(_("tag '%s' does not exist")
2134 % pattern)
2155 % pattern)
2135 s = {repo[tn].rev()}
2156 s = {repo[tn].rev()}
2136 else:
2157 else:
2137 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2158 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2138 else:
2159 else:
2139 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2160 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2140 return subset & s
2161 return subset & s
2141
2162
2142 @predicate('tagged', safe=True)
2163 @predicate('tagged', safe=True)
2143 def tagged(repo, subset, x):
2164 def tagged(repo, subset, x):
2144 return tag(repo, subset, x)
2165 return tag(repo, subset, x)
2145
2166
2146 @predicate('unstable()', safe=True)
2167 @predicate('unstable()', safe=True)
2147 def unstable(repo, subset, x):
2168 def unstable(repo, subset, x):
2148 """Non-obsolete changesets with obsolete ancestors.
2169 """Non-obsolete changesets with obsolete ancestors.
2149 """
2170 """
2150 # i18n: "unstable" is a keyword
2171 # i18n: "unstable" is a keyword
2151 getargs(x, 0, 0, _("unstable takes no arguments"))
2172 getargs(x, 0, 0, _("unstable takes no arguments"))
2152 unstables = obsmod.getrevs(repo, 'unstable')
2173 unstables = obsmod.getrevs(repo, 'unstable')
2153 return subset & unstables
2174 return subset & unstables
2154
2175
2155
2176
2156 @predicate('user(string)', safe=True)
2177 @predicate('user(string)', safe=True)
2157 def user(repo, subset, x):
2178 def user(repo, subset, x):
2158 """User name contains string. The match is case-insensitive.
2179 """User name contains string. The match is case-insensitive.
2159
2180
2160 Pattern matching is supported for `string`. See
2181 Pattern matching is supported for `string`. See
2161 :hg:`help revisions.patterns`.
2182 :hg:`help revisions.patterns`.
2162 """
2183 """
2163 return author(repo, subset, x)
2184 return author(repo, subset, x)
2164
2185
2165 @predicate('wdir()', safe=True)
2186 @predicate('wdir()', safe=True)
2166 def wdir(repo, subset, x):
2187 def wdir(repo, subset, x):
2167 """Working directory. (EXPERIMENTAL)"""
2188 """Working directory. (EXPERIMENTAL)"""
2168 # i18n: "wdir" is a keyword
2189 # i18n: "wdir" is a keyword
2169 getargs(x, 0, 0, _("wdir takes no arguments"))
2190 getargs(x, 0, 0, _("wdir takes no arguments"))
2170 if node.wdirrev in subset or isinstance(subset, fullreposet):
2191 if node.wdirrev in subset or isinstance(subset, fullreposet):
2171 return baseset([node.wdirrev])
2192 return baseset([node.wdirrev])
2172 return baseset()
2193 return baseset()
2173
2194
2174 def _orderedlist(repo, subset, x):
2195 def _orderedlist(repo, subset, x):
2175 s = getstring(x, "internal error")
2196 s = getstring(x, "internal error")
2176 if not s:
2197 if not s:
2177 return baseset()
2198 return baseset()
2178 # remove duplicates here. it's difficult for caller to deduplicate sets
2199 # remove duplicates here. it's difficult for caller to deduplicate sets
2179 # because different symbols can point to the same rev.
2200 # because different symbols can point to the same rev.
2180 cl = repo.changelog
2201 cl = repo.changelog
2181 ls = []
2202 ls = []
2182 seen = set()
2203 seen = set()
2183 for t in s.split('\0'):
2204 for t in s.split('\0'):
2184 try:
2205 try:
2185 # fast path for integer revision
2206 # fast path for integer revision
2186 r = int(t)
2207 r = int(t)
2187 if str(r) != t or r not in cl:
2208 if str(r) != t or r not in cl:
2188 raise ValueError
2209 raise ValueError
2189 revs = [r]
2210 revs = [r]
2190 except ValueError:
2211 except ValueError:
2191 revs = stringset(repo, subset, t)
2212 revs = stringset(repo, subset, t)
2192
2213
2193 for r in revs:
2214 for r in revs:
2194 if r in seen:
2215 if r in seen:
2195 continue
2216 continue
2196 if (r in subset
2217 if (r in subset
2197 or r == node.nullrev and isinstance(subset, fullreposet)):
2218 or r == node.nullrev and isinstance(subset, fullreposet)):
2198 ls.append(r)
2219 ls.append(r)
2199 seen.add(r)
2220 seen.add(r)
2200 return baseset(ls)
2221 return baseset(ls)
2201
2222
2202 # for internal use
2223 # for internal use
2203 @predicate('_list', safe=True, takeorder=True)
2224 @predicate('_list', safe=True, takeorder=True)
2204 def _list(repo, subset, x, order):
2225 def _list(repo, subset, x, order):
2205 if order == followorder:
2226 if order == followorder:
2206 # slow path to take the subset order
2227 # slow path to take the subset order
2207 return subset & _orderedlist(repo, fullreposet(repo), x)
2228 return subset & _orderedlist(repo, fullreposet(repo), x)
2208 else:
2229 else:
2209 return _orderedlist(repo, subset, x)
2230 return _orderedlist(repo, subset, x)
2210
2231
2211 def _orderedintlist(repo, subset, x):
2232 def _orderedintlist(repo, subset, x):
2212 s = getstring(x, "internal error")
2233 s = getstring(x, "internal error")
2213 if not s:
2234 if not s:
2214 return baseset()
2235 return baseset()
2215 ls = [int(r) for r in s.split('\0')]
2236 ls = [int(r) for r in s.split('\0')]
2216 s = subset
2237 s = subset
2217 return baseset([r for r in ls if r in s])
2238 return baseset([r for r in ls if r in s])
2218
2239
2219 # for internal use
2240 # for internal use
2220 @predicate('_intlist', safe=True, takeorder=True)
2241 @predicate('_intlist', safe=True, takeorder=True)
2221 def _intlist(repo, subset, x, order):
2242 def _intlist(repo, subset, x, order):
2222 if order == followorder:
2243 if order == followorder:
2223 # slow path to take the subset order
2244 # slow path to take the subset order
2224 return subset & _orderedintlist(repo, fullreposet(repo), x)
2245 return subset & _orderedintlist(repo, fullreposet(repo), x)
2225 else:
2246 else:
2226 return _orderedintlist(repo, subset, x)
2247 return _orderedintlist(repo, subset, x)
2227
2248
2228 def _orderedhexlist(repo, subset, x):
2249 def _orderedhexlist(repo, subset, x):
2229 s = getstring(x, "internal error")
2250 s = getstring(x, "internal error")
2230 if not s:
2251 if not s:
2231 return baseset()
2252 return baseset()
2232 cl = repo.changelog
2253 cl = repo.changelog
2233 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2254 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2234 s = subset
2255 s = subset
2235 return baseset([r for r in ls if r in s])
2256 return baseset([r for r in ls if r in s])
2236
2257
2237 # for internal use
2258 # for internal use
2238 @predicate('_hexlist', safe=True, takeorder=True)
2259 @predicate('_hexlist', safe=True, takeorder=True)
2239 def _hexlist(repo, subset, x, order):
2260 def _hexlist(repo, subset, x, order):
2240 if order == followorder:
2261 if order == followorder:
2241 # slow path to take the subset order
2262 # slow path to take the subset order
2242 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2263 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2243 else:
2264 else:
2244 return _orderedhexlist(repo, subset, x)
2265 return _orderedhexlist(repo, subset, x)
2245
2266
2246 methods = {
2267 methods = {
2247 "range": rangeset,
2268 "range": rangeset,
2248 "rangeall": rangeall,
2269 "rangeall": rangeall,
2249 "rangepre": rangepre,
2270 "rangepre": rangepre,
2250 "rangepost": rangepost,
2271 "rangepost": rangepost,
2251 "dagrange": dagrange,
2272 "dagrange": dagrange,
2252 "string": stringset,
2273 "string": stringset,
2253 "symbol": stringset,
2274 "symbol": stringset,
2254 "and": andset,
2275 "and": andset,
2255 "or": orset,
2276 "or": orset,
2256 "not": notset,
2277 "not": notset,
2257 "difference": differenceset,
2278 "difference": differenceset,
2258 "list": listset,
2279 "list": listset,
2259 "keyvalue": keyvaluepair,
2280 "keyvalue": keyvaluepair,
2260 "func": func,
2281 "func": func,
2261 "ancestor": ancestorspec,
2282 "ancestor": ancestorspec,
2262 "parent": parentspec,
2283 "parent": parentspec,
2263 "parentpost": parentpost,
2284 "parentpost": parentpost,
2264 }
2285 }
2265
2286
2266 def posttreebuilthook(tree, repo):
2287 def posttreebuilthook(tree, repo):
2267 # hook for extensions to execute code on the optimized tree
2288 # hook for extensions to execute code on the optimized tree
2268 pass
2289 pass
2269
2290
2270 def match(ui, spec, repo=None, order=defineorder):
2291 def match(ui, spec, repo=None, order=defineorder):
2271 """Create a matcher for a single revision spec
2292 """Create a matcher for a single revision spec
2272
2293
2273 If order=followorder, a matcher takes the ordering specified by the input
2294 If order=followorder, a matcher takes the ordering specified by the input
2274 set.
2295 set.
2275 """
2296 """
2276 return matchany(ui, [spec], repo=repo, order=order)
2297 return matchany(ui, [spec], repo=repo, order=order)
2277
2298
2278 def matchany(ui, specs, repo=None, order=defineorder):
2299 def matchany(ui, specs, repo=None, order=defineorder):
2279 """Create a matcher that will include any revisions matching one of the
2300 """Create a matcher that will include any revisions matching one of the
2280 given specs
2301 given specs
2281
2302
2282 If order=followorder, a matcher takes the ordering specified by the input
2303 If order=followorder, a matcher takes the ordering specified by the input
2283 set.
2304 set.
2284 """
2305 """
2285 if not specs:
2306 if not specs:
2286 def mfunc(repo, subset=None):
2307 def mfunc(repo, subset=None):
2287 return baseset()
2308 return baseset()
2288 return mfunc
2309 return mfunc
2289 if not all(specs):
2310 if not all(specs):
2290 raise error.ParseError(_("empty query"))
2311 raise error.ParseError(_("empty query"))
2291 lookup = None
2312 lookup = None
2292 if repo:
2313 if repo:
2293 lookup = repo.__contains__
2314 lookup = repo.__contains__
2294 if len(specs) == 1:
2315 if len(specs) == 1:
2295 tree = revsetlang.parse(specs[0], lookup)
2316 tree = revsetlang.parse(specs[0], lookup)
2296 else:
2317 else:
2297 tree = ('or',
2318 tree = ('or',
2298 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2319 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs))
2299
2320
2300 if ui:
2321 if ui:
2301 tree = revsetlang.expandaliases(ui, tree)
2322 tree = revsetlang.expandaliases(ui, tree)
2302 tree = revsetlang.foldconcat(tree)
2323 tree = revsetlang.foldconcat(tree)
2303 tree = revsetlang.analyze(tree, order)
2324 tree = revsetlang.analyze(tree, order)
2304 tree = revsetlang.optimize(tree)
2325 tree = revsetlang.optimize(tree)
2305 posttreebuilthook(tree, repo)
2326 posttreebuilthook(tree, repo)
2306 return makematcher(tree)
2327 return makematcher(tree)
2307
2328
2308 def makematcher(tree):
2329 def makematcher(tree):
2309 """Create a matcher from an evaluatable tree"""
2330 """Create a matcher from an evaluatable tree"""
2310 def mfunc(repo, subset=None):
2331 def mfunc(repo, subset=None):
2311 if subset is None:
2332 if subset is None:
2312 subset = fullreposet(repo)
2333 subset = fullreposet(repo)
2313 return getset(repo, subset, tree)
2334 return getset(repo, subset, tree)
2314 return mfunc
2335 return mfunc
2315
2336
2316 def loadpredicate(ui, extname, registrarobj):
2337 def loadpredicate(ui, extname, registrarobj):
2317 """Load revset predicates from specified registrarobj
2338 """Load revset predicates from specified registrarobj
2318 """
2339 """
2319 for name, func in registrarobj._table.iteritems():
2340 for name, func in registrarobj._table.iteritems():
2320 symbols[name] = func
2341 symbols[name] = func
2321 if func._safe:
2342 if func._safe:
2322 safesymbols.add(name)
2343 safesymbols.add(name)
2323
2344
2324 # load built-in predicates explicitly to setup safesymbols
2345 # load built-in predicates explicitly to setup safesymbols
2325 loadpredicate(None, None, predicate)
2346 loadpredicate(None, None, predicate)
2326
2347
2327 # tell hggettext to extract docstrings from these functions:
2348 # tell hggettext to extract docstrings from these functions:
2328 i18nfunctions = symbols.values()
2349 i18nfunctions = symbols.values()
@@ -1,3850 +1,3862
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3 $ cat > testrevset.py << EOF
3 $ cat > testrevset.py << EOF
4 > import mercurial.revset
4 > import mercurial.revset
5 >
5 >
6 > baseset = mercurial.revset.baseset
6 > baseset = mercurial.revset.baseset
7 >
7 >
8 > def r3232(repo, subset, x):
8 > def r3232(repo, subset, x):
9 > """"simple revset that return [3,2,3,2]
9 > """"simple revset that return [3,2,3,2]
10 >
10 >
11 > revisions duplicated on purpose.
11 > revisions duplicated on purpose.
12 > """
12 > """
13 > if 3 not in subset:
13 > if 3 not in subset:
14 > if 2 in subset:
14 > if 2 in subset:
15 > return baseset([2,2])
15 > return baseset([2,2])
16 > return baseset()
16 > return baseset()
17 > return baseset([3,3,2,2])
17 > return baseset([3,3,2,2])
18 >
18 >
19 > mercurial.revset.symbols['r3232'] = r3232
19 > mercurial.revset.symbols['r3232'] = r3232
20 > EOF
20 > EOF
21 $ cat >> $HGRCPATH << EOF
21 $ cat >> $HGRCPATH << EOF
22 > [extensions]
22 > [extensions]
23 > testrevset=$TESTTMP/testrevset.py
23 > testrevset=$TESTTMP/testrevset.py
24 > EOF
24 > EOF
25
25
26 $ try() {
26 $ try() {
27 > hg debugrevspec --debug "$@"
27 > hg debugrevspec --debug "$@"
28 > }
28 > }
29
29
30 $ log() {
30 $ log() {
31 > hg log --template '{rev}\n' -r "$1"
31 > hg log --template '{rev}\n' -r "$1"
32 > }
32 > }
33
33
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
34 extension to build '_intlist()' and '_hexlist()', which is necessary because
35 these predicates use '\0' as a separator:
35 these predicates use '\0' as a separator:
36
36
37 $ cat <<EOF > debugrevlistspec.py
37 $ cat <<EOF > debugrevlistspec.py
38 > from __future__ import absolute_import
38 > from __future__ import absolute_import
39 > from mercurial import (
39 > from mercurial import (
40 > node as nodemod,
40 > node as nodemod,
41 > registrar,
41 > registrar,
42 > revset,
42 > revset,
43 > revsetlang,
43 > revsetlang,
44 > smartset,
44 > smartset,
45 > )
45 > )
46 > cmdtable = {}
46 > cmdtable = {}
47 > command = registrar.command(cmdtable)
47 > command = registrar.command(cmdtable)
48 > @command('debugrevlistspec',
48 > @command('debugrevlistspec',
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
49 > [('', 'optimize', None, 'print parsed tree after optimizing'),
50 > ('', 'bin', None, 'unhexlify arguments')])
50 > ('', 'bin', None, 'unhexlify arguments')])
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
51 > def debugrevlistspec(ui, repo, fmt, *args, **opts):
52 > if opts['bin']:
52 > if opts['bin']:
53 > args = map(nodemod.bin, args)
53 > args = map(nodemod.bin, args)
54 > expr = revsetlang.formatspec(fmt, list(args))
54 > expr = revsetlang.formatspec(fmt, list(args))
55 > if ui.verbose:
55 > if ui.verbose:
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
56 > tree = revsetlang.parse(expr, lookup=repo.__contains__)
57 > ui.note(revsetlang.prettyformat(tree), "\n")
57 > ui.note(revsetlang.prettyformat(tree), "\n")
58 > if opts["optimize"]:
58 > if opts["optimize"]:
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
59 > opttree = revsetlang.optimize(revsetlang.analyze(tree))
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
60 > ui.note("* optimized:\n", revsetlang.prettyformat(opttree),
61 > "\n")
61 > "\n")
62 > func = revset.match(ui, expr, repo)
62 > func = revset.match(ui, expr, repo)
63 > revs = func(repo)
63 > revs = func(repo)
64 > if ui.verbose:
64 > if ui.verbose:
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
65 > ui.note("* set:\n", smartset.prettyformat(revs), "\n")
66 > for c in revs:
66 > for c in revs:
67 > ui.write("%s\n" % c)
67 > ui.write("%s\n" % c)
68 > EOF
68 > EOF
69 $ cat <<EOF >> $HGRCPATH
69 $ cat <<EOF >> $HGRCPATH
70 > [extensions]
70 > [extensions]
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
71 > debugrevlistspec = $TESTTMP/debugrevlistspec.py
72 > EOF
72 > EOF
73 $ trylist() {
73 $ trylist() {
74 > hg debugrevlistspec --debug "$@"
74 > hg debugrevlistspec --debug "$@"
75 > }
75 > }
76
76
77 $ hg init repo
77 $ hg init repo
78 $ cd repo
78 $ cd repo
79
79
80 $ echo a > a
80 $ echo a > a
81 $ hg branch a
81 $ hg branch a
82 marked working directory as branch a
82 marked working directory as branch a
83 (branches are permanent and global, did you want a bookmark?)
83 (branches are permanent and global, did you want a bookmark?)
84 $ hg ci -Aqm0
84 $ hg ci -Aqm0
85
85
86 $ echo b > b
86 $ echo b > b
87 $ hg branch b
87 $ hg branch b
88 marked working directory as branch b
88 marked working directory as branch b
89 $ hg ci -Aqm1
89 $ hg ci -Aqm1
90
90
91 $ rm a
91 $ rm a
92 $ hg branch a-b-c-
92 $ hg branch a-b-c-
93 marked working directory as branch a-b-c-
93 marked working directory as branch a-b-c-
94 $ hg ci -Aqm2 -u Bob
94 $ hg ci -Aqm2 -u Bob
95
95
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
96 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
97 2
97 2
98 $ hg log -r "extra('branch')" --template '{rev}\n'
98 $ hg log -r "extra('branch')" --template '{rev}\n'
99 0
99 0
100 1
100 1
101 2
101 2
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
102 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
103 0 a
103 0 a
104 2 a-b-c-
104 2 a-b-c-
105
105
106 $ hg co 1
106 $ hg co 1
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 $ hg branch +a+b+c+
108 $ hg branch +a+b+c+
109 marked working directory as branch +a+b+c+
109 marked working directory as branch +a+b+c+
110 $ hg ci -Aqm3
110 $ hg ci -Aqm3
111
111
112 $ hg co 2 # interleave
112 $ hg co 2 # interleave
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 $ echo bb > b
114 $ echo bb > b
115 $ hg branch -- -a-b-c-
115 $ hg branch -- -a-b-c-
116 marked working directory as branch -a-b-c-
116 marked working directory as branch -a-b-c-
117 $ hg ci -Aqm4 -d "May 12 2005"
117 $ hg ci -Aqm4 -d "May 12 2005"
118
118
119 $ hg co 3
119 $ hg co 3
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 $ hg branch !a/b/c/
121 $ hg branch !a/b/c/
122 marked working directory as branch !a/b/c/
122 marked working directory as branch !a/b/c/
123 $ hg ci -Aqm"5 bug"
123 $ hg ci -Aqm"5 bug"
124
124
125 $ hg merge 4
125 $ hg merge 4
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 (branch merge, don't forget to commit)
127 (branch merge, don't forget to commit)
128 $ hg branch _a_b_c_
128 $ hg branch _a_b_c_
129 marked working directory as branch _a_b_c_
129 marked working directory as branch _a_b_c_
130 $ hg ci -Aqm"6 issue619"
130 $ hg ci -Aqm"6 issue619"
131
131
132 $ hg branch .a.b.c.
132 $ hg branch .a.b.c.
133 marked working directory as branch .a.b.c.
133 marked working directory as branch .a.b.c.
134 $ hg ci -Aqm7
134 $ hg ci -Aqm7
135
135
136 $ hg branch all
136 $ hg branch all
137 marked working directory as branch all
137 marked working directory as branch all
138
138
139 $ hg co 4
139 $ hg co 4
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 $ hg branch é
141 $ hg branch é
142 marked working directory as branch \xc3\xa9 (esc)
142 marked working directory as branch \xc3\xa9 (esc)
143 $ hg ci -Aqm9
143 $ hg ci -Aqm9
144
144
145 $ hg tag -r6 1.0
145 $ hg tag -r6 1.0
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
146 $ hg bookmark -r6 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
147
147
148 $ hg clone --quiet -U -r 7 . ../remote1
148 $ hg clone --quiet -U -r 7 . ../remote1
149 $ hg clone --quiet -U -r 8 . ../remote2
149 $ hg clone --quiet -U -r 8 . ../remote2
150 $ echo "[paths]" >> .hg/hgrc
150 $ echo "[paths]" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
151 $ echo "default = ../remote1" >> .hg/hgrc
152
152
153 trivial
153 trivial
154
154
155 $ try 0:1
155 $ try 0:1
156 (range
156 (range
157 ('symbol', '0')
157 ('symbol', '0')
158 ('symbol', '1'))
158 ('symbol', '1'))
159 * set:
159 * set:
160 <spanset+ 0:1>
160 <spanset+ 0:1>
161 0
161 0
162 1
162 1
163 $ try --optimize :
163 $ try --optimize :
164 (rangeall
164 (rangeall
165 None)
165 None)
166 * optimized:
166 * optimized:
167 (rangeall
167 (rangeall
168 None
168 None
169 define)
169 define)
170 * set:
170 * set:
171 <spanset+ 0:9>
171 <spanset+ 0:9>
172 0
172 0
173 1
173 1
174 2
174 2
175 3
175 3
176 4
176 4
177 5
177 5
178 6
178 6
179 7
179 7
180 8
180 8
181 9
181 9
182 $ try 3::6
182 $ try 3::6
183 (dagrange
183 (dagrange
184 ('symbol', '3')
184 ('symbol', '3')
185 ('symbol', '6'))
185 ('symbol', '6'))
186 * set:
186 * set:
187 <baseset+ [3, 5, 6]>
187 <baseset+ [3, 5, 6]>
188 3
188 3
189 5
189 5
190 6
190 6
191 $ try '0|1|2'
191 $ try '0|1|2'
192 (or
192 (or
193 (list
193 (list
194 ('symbol', '0')
194 ('symbol', '0')
195 ('symbol', '1')
195 ('symbol', '1')
196 ('symbol', '2')))
196 ('symbol', '2')))
197 * set:
197 * set:
198 <baseset [0, 1, 2]>
198 <baseset [0, 1, 2]>
199 0
199 0
200 1
200 1
201 2
201 2
202
202
203 names that should work without quoting
203 names that should work without quoting
204
204
205 $ try a
205 $ try a
206 ('symbol', 'a')
206 ('symbol', 'a')
207 * set:
207 * set:
208 <baseset [0]>
208 <baseset [0]>
209 0
209 0
210 $ try b-a
210 $ try b-a
211 (minus
211 (minus
212 ('symbol', 'b')
212 ('symbol', 'b')
213 ('symbol', 'a'))
213 ('symbol', 'a'))
214 * set:
214 * set:
215 <filteredset
215 <filteredset
216 <baseset [1]>,
216 <baseset [1]>,
217 <not
217 <not
218 <baseset [0]>>>
218 <baseset [0]>>>
219 1
219 1
220 $ try _a_b_c_
220 $ try _a_b_c_
221 ('symbol', '_a_b_c_')
221 ('symbol', '_a_b_c_')
222 * set:
222 * set:
223 <baseset [6]>
223 <baseset [6]>
224 6
224 6
225 $ try _a_b_c_-a
225 $ try _a_b_c_-a
226 (minus
226 (minus
227 ('symbol', '_a_b_c_')
227 ('symbol', '_a_b_c_')
228 ('symbol', 'a'))
228 ('symbol', 'a'))
229 * set:
229 * set:
230 <filteredset
230 <filteredset
231 <baseset [6]>,
231 <baseset [6]>,
232 <not
232 <not
233 <baseset [0]>>>
233 <baseset [0]>>>
234 6
234 6
235 $ try .a.b.c.
235 $ try .a.b.c.
236 ('symbol', '.a.b.c.')
236 ('symbol', '.a.b.c.')
237 * set:
237 * set:
238 <baseset [7]>
238 <baseset [7]>
239 7
239 7
240 $ try .a.b.c.-a
240 $ try .a.b.c.-a
241 (minus
241 (minus
242 ('symbol', '.a.b.c.')
242 ('symbol', '.a.b.c.')
243 ('symbol', 'a'))
243 ('symbol', 'a'))
244 * set:
244 * set:
245 <filteredset
245 <filteredset
246 <baseset [7]>,
246 <baseset [7]>,
247 <not
247 <not
248 <baseset [0]>>>
248 <baseset [0]>>>
249 7
249 7
250
250
251 names that should be caught by fallback mechanism
251 names that should be caught by fallback mechanism
252
252
253 $ try -- '-a-b-c-'
253 $ try -- '-a-b-c-'
254 ('symbol', '-a-b-c-')
254 ('symbol', '-a-b-c-')
255 * set:
255 * set:
256 <baseset [4]>
256 <baseset [4]>
257 4
257 4
258 $ log -a-b-c-
258 $ log -a-b-c-
259 4
259 4
260 $ try '+a+b+c+'
260 $ try '+a+b+c+'
261 ('symbol', '+a+b+c+')
261 ('symbol', '+a+b+c+')
262 * set:
262 * set:
263 <baseset [3]>
263 <baseset [3]>
264 3
264 3
265 $ try '+a+b+c+:'
265 $ try '+a+b+c+:'
266 (rangepost
266 (rangepost
267 ('symbol', '+a+b+c+'))
267 ('symbol', '+a+b+c+'))
268 * set:
268 * set:
269 <spanset+ 3:9>
269 <spanset+ 3:9>
270 3
270 3
271 4
271 4
272 5
272 5
273 6
273 6
274 7
274 7
275 8
275 8
276 9
276 9
277 $ try ':+a+b+c+'
277 $ try ':+a+b+c+'
278 (rangepre
278 (rangepre
279 ('symbol', '+a+b+c+'))
279 ('symbol', '+a+b+c+'))
280 * set:
280 * set:
281 <spanset+ 0:3>
281 <spanset+ 0:3>
282 0
282 0
283 1
283 1
284 2
284 2
285 3
285 3
286 $ try -- '-a-b-c-:+a+b+c+'
286 $ try -- '-a-b-c-:+a+b+c+'
287 (range
287 (range
288 ('symbol', '-a-b-c-')
288 ('symbol', '-a-b-c-')
289 ('symbol', '+a+b+c+'))
289 ('symbol', '+a+b+c+'))
290 * set:
290 * set:
291 <spanset- 3:4>
291 <spanset- 3:4>
292 4
292 4
293 3
293 3
294 $ log '-a-b-c-:+a+b+c+'
294 $ log '-a-b-c-:+a+b+c+'
295 4
295 4
296 3
296 3
297
297
298 $ try -- -a-b-c--a # complains
298 $ try -- -a-b-c--a # complains
299 (minus
299 (minus
300 (minus
300 (minus
301 (minus
301 (minus
302 (negate
302 (negate
303 ('symbol', 'a'))
303 ('symbol', 'a'))
304 ('symbol', 'b'))
304 ('symbol', 'b'))
305 ('symbol', 'c'))
305 ('symbol', 'c'))
306 (negate
306 (negate
307 ('symbol', 'a')))
307 ('symbol', 'a')))
308 abort: unknown revision '-a'!
308 abort: unknown revision '-a'!
309 [255]
309 [255]
310 $ try é
310 $ try é
311 ('symbol', '\xc3\xa9')
311 ('symbol', '\xc3\xa9')
312 * set:
312 * set:
313 <baseset [9]>
313 <baseset [9]>
314 9
314 9
315
315
316 no quoting needed
316 no quoting needed
317
317
318 $ log ::a-b-c-
318 $ log ::a-b-c-
319 0
319 0
320 1
320 1
321 2
321 2
322
322
323 quoting needed
323 quoting needed
324
324
325 $ try '"-a-b-c-"-a'
325 $ try '"-a-b-c-"-a'
326 (minus
326 (minus
327 ('string', '-a-b-c-')
327 ('string', '-a-b-c-')
328 ('symbol', 'a'))
328 ('symbol', 'a'))
329 * set:
329 * set:
330 <filteredset
330 <filteredset
331 <baseset [4]>,
331 <baseset [4]>,
332 <not
332 <not
333 <baseset [0]>>>
333 <baseset [0]>>>
334 4
334 4
335
335
336 $ log '1 or 2'
336 $ log '1 or 2'
337 1
337 1
338 2
338 2
339 $ log '1|2'
339 $ log '1|2'
340 1
340 1
341 2
341 2
342 $ log '1 and 2'
342 $ log '1 and 2'
343 $ log '1&2'
343 $ log '1&2'
344 $ try '1&2|3' # precedence - and is higher
344 $ try '1&2|3' # precedence - and is higher
345 (or
345 (or
346 (list
346 (list
347 (and
347 (and
348 ('symbol', '1')
348 ('symbol', '1')
349 ('symbol', '2'))
349 ('symbol', '2'))
350 ('symbol', '3')))
350 ('symbol', '3')))
351 * set:
351 * set:
352 <addset
352 <addset
353 <baseset []>,
353 <baseset []>,
354 <baseset [3]>>
354 <baseset [3]>>
355 3
355 3
356 $ try '1|2&3'
356 $ try '1|2&3'
357 (or
357 (or
358 (list
358 (list
359 ('symbol', '1')
359 ('symbol', '1')
360 (and
360 (and
361 ('symbol', '2')
361 ('symbol', '2')
362 ('symbol', '3'))))
362 ('symbol', '3'))))
363 * set:
363 * set:
364 <addset
364 <addset
365 <baseset [1]>,
365 <baseset [1]>,
366 <baseset []>>
366 <baseset []>>
367 1
367 1
368 $ try '1&2&3' # associativity
368 $ try '1&2&3' # associativity
369 (and
369 (and
370 (and
370 (and
371 ('symbol', '1')
371 ('symbol', '1')
372 ('symbol', '2'))
372 ('symbol', '2'))
373 ('symbol', '3'))
373 ('symbol', '3'))
374 * set:
374 * set:
375 <baseset []>
375 <baseset []>
376 $ try '1|(2|3)'
376 $ try '1|(2|3)'
377 (or
377 (or
378 (list
378 (list
379 ('symbol', '1')
379 ('symbol', '1')
380 (group
380 (group
381 (or
381 (or
382 (list
382 (list
383 ('symbol', '2')
383 ('symbol', '2')
384 ('symbol', '3'))))))
384 ('symbol', '3'))))))
385 * set:
385 * set:
386 <addset
386 <addset
387 <baseset [1]>,
387 <baseset [1]>,
388 <baseset [2, 3]>>
388 <baseset [2, 3]>>
389 1
389 1
390 2
390 2
391 3
391 3
392 $ log '1.0' # tag
392 $ log '1.0' # tag
393 6
393 6
394 $ log 'a' # branch
394 $ log 'a' # branch
395 0
395 0
396 $ log '2785f51ee'
396 $ log '2785f51ee'
397 0
397 0
398 $ log 'date(2005)'
398 $ log 'date(2005)'
399 4
399 4
400 $ log 'date(this is a test)'
400 $ log 'date(this is a test)'
401 hg: parse error at 10: unexpected token: symbol
401 hg: parse error at 10: unexpected token: symbol
402 [255]
402 [255]
403 $ log 'date()'
403 $ log 'date()'
404 hg: parse error: date requires a string
404 hg: parse error: date requires a string
405 [255]
405 [255]
406 $ log 'date'
406 $ log 'date'
407 abort: unknown revision 'date'!
407 abort: unknown revision 'date'!
408 [255]
408 [255]
409 $ log 'date('
409 $ log 'date('
410 hg: parse error at 5: not a prefix: end
410 hg: parse error at 5: not a prefix: end
411 [255]
411 [255]
412 $ log 'date("\xy")'
412 $ log 'date("\xy")'
413 hg: parse error: invalid \x escape
413 hg: parse error: invalid \x escape
414 [255]
414 [255]
415 $ log 'date(tip)'
415 $ log 'date(tip)'
416 hg: parse error: invalid date: 'tip'
416 hg: parse error: invalid date: 'tip'
417 [255]
417 [255]
418 $ log '0:date'
418 $ log '0:date'
419 abort: unknown revision 'date'!
419 abort: unknown revision 'date'!
420 [255]
420 [255]
421 $ log '::"date"'
421 $ log '::"date"'
422 abort: unknown revision 'date'!
422 abort: unknown revision 'date'!
423 [255]
423 [255]
424 $ hg book date -r 4
424 $ hg book date -r 4
425 $ log '0:date'
425 $ log '0:date'
426 0
426 0
427 1
427 1
428 2
428 2
429 3
429 3
430 4
430 4
431 $ log '::date'
431 $ log '::date'
432 0
432 0
433 1
433 1
434 2
434 2
435 4
435 4
436 $ log '::"date"'
436 $ log '::"date"'
437 0
437 0
438 1
438 1
439 2
439 2
440 4
440 4
441 $ log 'date(2005) and 1::'
441 $ log 'date(2005) and 1::'
442 4
442 4
443 $ hg book -d date
443 $ hg book -d date
444
444
445 function name should be a symbol
445 function name should be a symbol
446
446
447 $ log '"date"(2005)'
447 $ log '"date"(2005)'
448 hg: parse error: not a symbol
448 hg: parse error: not a symbol
449 [255]
449 [255]
450
450
451 keyword arguments
451 keyword arguments
452
452
453 $ log 'extra(branch, value=a)'
453 $ log 'extra(branch, value=a)'
454 0
454 0
455
455
456 $ log 'extra(branch, a, b)'
456 $ log 'extra(branch, a, b)'
457 hg: parse error: extra takes at most 2 positional arguments
457 hg: parse error: extra takes at most 2 positional arguments
458 [255]
458 [255]
459 $ log 'extra(a, label=b)'
459 $ log 'extra(a, label=b)'
460 hg: parse error: extra got multiple values for keyword argument 'label'
460 hg: parse error: extra got multiple values for keyword argument 'label'
461 [255]
461 [255]
462 $ log 'extra(label=branch, default)'
462 $ log 'extra(label=branch, default)'
463 hg: parse error: extra got an invalid argument
463 hg: parse error: extra got an invalid argument
464 [255]
464 [255]
465 $ log 'extra(branch, foo+bar=baz)'
465 $ log 'extra(branch, foo+bar=baz)'
466 hg: parse error: extra got an invalid argument
466 hg: parse error: extra got an invalid argument
467 [255]
467 [255]
468 $ log 'extra(unknown=branch)'
468 $ log 'extra(unknown=branch)'
469 hg: parse error: extra got an unexpected keyword argument 'unknown'
469 hg: parse error: extra got an unexpected keyword argument 'unknown'
470 [255]
470 [255]
471
471
472 $ try 'foo=bar|baz'
472 $ try 'foo=bar|baz'
473 (keyvalue
473 (keyvalue
474 ('symbol', 'foo')
474 ('symbol', 'foo')
475 (or
475 (or
476 (list
476 (list
477 ('symbol', 'bar')
477 ('symbol', 'bar')
478 ('symbol', 'baz'))))
478 ('symbol', 'baz'))))
479 hg: parse error: can't use a key-value pair in this context
479 hg: parse error: can't use a key-value pair in this context
480 [255]
480 [255]
481
481
482 right-hand side should be optimized recursively
482 right-hand side should be optimized recursively
483
483
484 $ try --optimize 'foo=(not public())'
484 $ try --optimize 'foo=(not public())'
485 (keyvalue
485 (keyvalue
486 ('symbol', 'foo')
486 ('symbol', 'foo')
487 (group
487 (group
488 (not
488 (not
489 (func
489 (func
490 ('symbol', 'public')
490 ('symbol', 'public')
491 None))))
491 None))))
492 * optimized:
492 * optimized:
493 (keyvalue
493 (keyvalue
494 ('symbol', 'foo')
494 ('symbol', 'foo')
495 (func
495 (func
496 ('symbol', '_notpublic')
496 ('symbol', '_notpublic')
497 None
497 None
498 any))
498 any))
499 hg: parse error: can't use a key-value pair in this context
499 hg: parse error: can't use a key-value pair in this context
500 [255]
500 [255]
501
501
502 parsed tree at stages:
502 parsed tree at stages:
503
503
504 $ hg debugrevspec -p all '()'
504 $ hg debugrevspec -p all '()'
505 * parsed:
505 * parsed:
506 (group
506 (group
507 None)
507 None)
508 * expanded:
508 * expanded:
509 (group
509 (group
510 None)
510 None)
511 * concatenated:
511 * concatenated:
512 (group
512 (group
513 None)
513 None)
514 * analyzed:
514 * analyzed:
515 None
515 None
516 * optimized:
516 * optimized:
517 None
517 None
518 hg: parse error: missing argument
518 hg: parse error: missing argument
519 [255]
519 [255]
520
520
521 $ hg debugrevspec --no-optimized -p all '()'
521 $ hg debugrevspec --no-optimized -p all '()'
522 * parsed:
522 * parsed:
523 (group
523 (group
524 None)
524 None)
525 * expanded:
525 * expanded:
526 (group
526 (group
527 None)
527 None)
528 * concatenated:
528 * concatenated:
529 (group
529 (group
530 None)
530 None)
531 * analyzed:
531 * analyzed:
532 None
532 None
533 hg: parse error: missing argument
533 hg: parse error: missing argument
534 [255]
534 [255]
535
535
536 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
536 $ hg debugrevspec -p parsed -p analyzed -p optimized '(0|1)-1'
537 * parsed:
537 * parsed:
538 (minus
538 (minus
539 (group
539 (group
540 (or
540 (or
541 (list
541 (list
542 ('symbol', '0')
542 ('symbol', '0')
543 ('symbol', '1'))))
543 ('symbol', '1'))))
544 ('symbol', '1'))
544 ('symbol', '1'))
545 * analyzed:
545 * analyzed:
546 (and
546 (and
547 (or
547 (or
548 (list
548 (list
549 ('symbol', '0')
549 ('symbol', '0')
550 ('symbol', '1'))
550 ('symbol', '1'))
551 define)
551 define)
552 (not
552 (not
553 ('symbol', '1')
553 ('symbol', '1')
554 follow)
554 follow)
555 define)
555 define)
556 * optimized:
556 * optimized:
557 (difference
557 (difference
558 (func
558 (func
559 ('symbol', '_list')
559 ('symbol', '_list')
560 ('string', '0\x001')
560 ('string', '0\x001')
561 define)
561 define)
562 ('symbol', '1')
562 ('symbol', '1')
563 define)
563 define)
564 0
564 0
565
565
566 $ hg debugrevspec -p unknown '0'
566 $ hg debugrevspec -p unknown '0'
567 abort: invalid stage name: unknown
567 abort: invalid stage name: unknown
568 [255]
568 [255]
569
569
570 $ hg debugrevspec -p all --optimize '0'
570 $ hg debugrevspec -p all --optimize '0'
571 abort: cannot use --optimize with --show-stage
571 abort: cannot use --optimize with --show-stage
572 [255]
572 [255]
573
573
574 verify optimized tree:
574 verify optimized tree:
575
575
576 $ hg debugrevspec --verify '0|1'
576 $ hg debugrevspec --verify '0|1'
577
577
578 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
578 $ hg debugrevspec --verify -v -p analyzed -p optimized 'r3232() & 2'
579 * analyzed:
579 * analyzed:
580 (and
580 (and
581 (func
581 (func
582 ('symbol', 'r3232')
582 ('symbol', 'r3232')
583 None
583 None
584 define)
584 define)
585 ('symbol', '2')
585 ('symbol', '2')
586 define)
586 define)
587 * optimized:
587 * optimized:
588 (and
588 (and
589 ('symbol', '2')
589 ('symbol', '2')
590 (func
590 (func
591 ('symbol', 'r3232')
591 ('symbol', 'r3232')
592 None
592 None
593 define)
593 define)
594 define)
594 define)
595 * analyzed set:
595 * analyzed set:
596 <baseset [2]>
596 <baseset [2]>
597 * optimized set:
597 * optimized set:
598 <baseset [2, 2]>
598 <baseset [2, 2]>
599 --- analyzed
599 --- analyzed
600 +++ optimized
600 +++ optimized
601 2
601 2
602 +2
602 +2
603 [1]
603 [1]
604
604
605 $ hg debugrevspec --no-optimized --verify-optimized '0'
605 $ hg debugrevspec --no-optimized --verify-optimized '0'
606 abort: cannot use --verify-optimized with --no-optimized
606 abort: cannot use --verify-optimized with --no-optimized
607 [255]
607 [255]
608
608
609 Test that symbols only get parsed as functions if there's an opening
609 Test that symbols only get parsed as functions if there's an opening
610 parenthesis.
610 parenthesis.
611
611
612 $ hg book only -r 9
612 $ hg book only -r 9
613 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
613 $ log 'only(only)' # Outer "only" is a function, inner "only" is the bookmark
614 8
614 8
615 9
615 9
616
616
617 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
617 ':y' behaves like '0:y', but can't be rewritten as such since the revision '0'
618 may be hidden (issue5385)
618 may be hidden (issue5385)
619
619
620 $ try -p parsed -p analyzed ':'
620 $ try -p parsed -p analyzed ':'
621 * parsed:
621 * parsed:
622 (rangeall
622 (rangeall
623 None)
623 None)
624 * analyzed:
624 * analyzed:
625 (rangeall
625 (rangeall
626 None
626 None
627 define)
627 define)
628 * set:
628 * set:
629 <spanset+ 0:9>
629 <spanset+ 0:9>
630 0
630 0
631 1
631 1
632 2
632 2
633 3
633 3
634 4
634 4
635 5
635 5
636 6
636 6
637 7
637 7
638 8
638 8
639 9
639 9
640 $ try -p analyzed ':1'
640 $ try -p analyzed ':1'
641 * analyzed:
641 * analyzed:
642 (rangepre
642 (rangepre
643 ('symbol', '1')
643 ('symbol', '1')
644 define)
644 define)
645 * set:
645 * set:
646 <spanset+ 0:1>
646 <spanset+ 0:1>
647 0
647 0
648 1
648 1
649 $ try -p analyzed ':(1|2)'
649 $ try -p analyzed ':(1|2)'
650 * analyzed:
650 * analyzed:
651 (rangepre
651 (rangepre
652 (or
652 (or
653 (list
653 (list
654 ('symbol', '1')
654 ('symbol', '1')
655 ('symbol', '2'))
655 ('symbol', '2'))
656 define)
656 define)
657 define)
657 define)
658 * set:
658 * set:
659 <spanset+ 0:2>
659 <spanset+ 0:2>
660 0
660 0
661 1
661 1
662 2
662 2
663 $ try -p analyzed ':(1&2)'
663 $ try -p analyzed ':(1&2)'
664 * analyzed:
664 * analyzed:
665 (rangepre
665 (rangepre
666 (and
666 (and
667 ('symbol', '1')
667 ('symbol', '1')
668 ('symbol', '2')
668 ('symbol', '2')
669 define)
669 define)
670 define)
670 define)
671 * set:
671 * set:
672 <baseset []>
672 <baseset []>
673
673
674 infix/suffix resolution of ^ operator (issue2884):
674 infix/suffix resolution of ^ operator (issue2884):
675
675
676 x^:y means (x^):y
676 x^:y means (x^):y
677
677
678 $ try '1^:2'
678 $ try '1^:2'
679 (range
679 (range
680 (parentpost
680 (parentpost
681 ('symbol', '1'))
681 ('symbol', '1'))
682 ('symbol', '2'))
682 ('symbol', '2'))
683 * set:
683 * set:
684 <spanset+ 0:2>
684 <spanset+ 0:2>
685 0
685 0
686 1
686 1
687 2
687 2
688
688
689 $ try '1^::2'
689 $ try '1^::2'
690 (dagrange
690 (dagrange
691 (parentpost
691 (parentpost
692 ('symbol', '1'))
692 ('symbol', '1'))
693 ('symbol', '2'))
693 ('symbol', '2'))
694 * set:
694 * set:
695 <baseset+ [0, 1, 2]>
695 <baseset+ [0, 1, 2]>
696 0
696 0
697 1
697 1
698 2
698 2
699
699
700 $ try '9^:'
700 $ try '9^:'
701 (rangepost
701 (rangepost
702 (parentpost
702 (parentpost
703 ('symbol', '9')))
703 ('symbol', '9')))
704 * set:
704 * set:
705 <spanset+ 8:9>
705 <spanset+ 8:9>
706 8
706 8
707 9
707 9
708
708
709 x^:y should be resolved before omitting group operators
709 x^:y should be resolved before omitting group operators
710
710
711 $ try '1^(:2)'
711 $ try '1^(:2)'
712 (parent
712 (parent
713 ('symbol', '1')
713 ('symbol', '1')
714 (group
714 (group
715 (rangepre
715 (rangepre
716 ('symbol', '2'))))
716 ('symbol', '2'))))
717 hg: parse error: ^ expects a number 0, 1, or 2
717 hg: parse error: ^ expects a number 0, 1, or 2
718 [255]
718 [255]
719
719
720 x^:y should be resolved recursively
720 x^:y should be resolved recursively
721
721
722 $ try 'sort(1^:2)'
722 $ try 'sort(1^:2)'
723 (func
723 (func
724 ('symbol', 'sort')
724 ('symbol', 'sort')
725 (range
725 (range
726 (parentpost
726 (parentpost
727 ('symbol', '1'))
727 ('symbol', '1'))
728 ('symbol', '2')))
728 ('symbol', '2')))
729 * set:
729 * set:
730 <spanset+ 0:2>
730 <spanset+ 0:2>
731 0
731 0
732 1
732 1
733 2
733 2
734
734
735 $ try '(3^:4)^:2'
735 $ try '(3^:4)^:2'
736 (range
736 (range
737 (parentpost
737 (parentpost
738 (group
738 (group
739 (range
739 (range
740 (parentpost
740 (parentpost
741 ('symbol', '3'))
741 ('symbol', '3'))
742 ('symbol', '4'))))
742 ('symbol', '4'))))
743 ('symbol', '2'))
743 ('symbol', '2'))
744 * set:
744 * set:
745 <spanset+ 0:2>
745 <spanset+ 0:2>
746 0
746 0
747 1
747 1
748 2
748 2
749
749
750 $ try '(3^::4)^::2'
750 $ try '(3^::4)^::2'
751 (dagrange
751 (dagrange
752 (parentpost
752 (parentpost
753 (group
753 (group
754 (dagrange
754 (dagrange
755 (parentpost
755 (parentpost
756 ('symbol', '3'))
756 ('symbol', '3'))
757 ('symbol', '4'))))
757 ('symbol', '4'))))
758 ('symbol', '2'))
758 ('symbol', '2'))
759 * set:
759 * set:
760 <baseset+ [0, 1, 2]>
760 <baseset+ [0, 1, 2]>
761 0
761 0
762 1
762 1
763 2
763 2
764
764
765 $ try '(9^:)^:'
765 $ try '(9^:)^:'
766 (rangepost
766 (rangepost
767 (parentpost
767 (parentpost
768 (group
768 (group
769 (rangepost
769 (rangepost
770 (parentpost
770 (parentpost
771 ('symbol', '9'))))))
771 ('symbol', '9'))))))
772 * set:
772 * set:
773 <spanset+ 4:9>
773 <spanset+ 4:9>
774 4
774 4
775 5
775 5
776 6
776 6
777 7
777 7
778 8
778 8
779 9
779 9
780
780
781 x^ in alias should also be resolved
781 x^ in alias should also be resolved
782
782
783 $ try 'A' --config 'revsetalias.A=1^:2'
783 $ try 'A' --config 'revsetalias.A=1^:2'
784 ('symbol', 'A')
784 ('symbol', 'A')
785 * expanded:
785 * expanded:
786 (range
786 (range
787 (parentpost
787 (parentpost
788 ('symbol', '1'))
788 ('symbol', '1'))
789 ('symbol', '2'))
789 ('symbol', '2'))
790 * set:
790 * set:
791 <spanset+ 0:2>
791 <spanset+ 0:2>
792 0
792 0
793 1
793 1
794 2
794 2
795
795
796 $ try 'A:2' --config 'revsetalias.A=1^'
796 $ try 'A:2' --config 'revsetalias.A=1^'
797 (range
797 (range
798 ('symbol', 'A')
798 ('symbol', 'A')
799 ('symbol', '2'))
799 ('symbol', '2'))
800 * expanded:
800 * expanded:
801 (range
801 (range
802 (parentpost
802 (parentpost
803 ('symbol', '1'))
803 ('symbol', '1'))
804 ('symbol', '2'))
804 ('symbol', '2'))
805 * set:
805 * set:
806 <spanset+ 0:2>
806 <spanset+ 0:2>
807 0
807 0
808 1
808 1
809 2
809 2
810
810
811 but not beyond the boundary of alias expansion, because the resolution should
811 but not beyond the boundary of alias expansion, because the resolution should
812 be made at the parsing stage
812 be made at the parsing stage
813
813
814 $ try '1^A' --config 'revsetalias.A=:2'
814 $ try '1^A' --config 'revsetalias.A=:2'
815 (parent
815 (parent
816 ('symbol', '1')
816 ('symbol', '1')
817 ('symbol', 'A'))
817 ('symbol', 'A'))
818 * expanded:
818 * expanded:
819 (parent
819 (parent
820 ('symbol', '1')
820 ('symbol', '1')
821 (rangepre
821 (rangepre
822 ('symbol', '2')))
822 ('symbol', '2')))
823 hg: parse error: ^ expects a number 0, 1, or 2
823 hg: parse error: ^ expects a number 0, 1, or 2
824 [255]
824 [255]
825
825
826 ancestor can accept 0 or more arguments
826 ancestor can accept 0 or more arguments
827
827
828 $ log 'ancestor()'
828 $ log 'ancestor()'
829 $ log 'ancestor(1)'
829 $ log 'ancestor(1)'
830 1
830 1
831 $ log 'ancestor(4,5)'
831 $ log 'ancestor(4,5)'
832 1
832 1
833 $ log 'ancestor(4,5) and 4'
833 $ log 'ancestor(4,5) and 4'
834 $ log 'ancestor(0,0,1,3)'
834 $ log 'ancestor(0,0,1,3)'
835 0
835 0
836 $ log 'ancestor(3,1,5,3,5,1)'
836 $ log 'ancestor(3,1,5,3,5,1)'
837 1
837 1
838 $ log 'ancestor(0,1,3,5)'
838 $ log 'ancestor(0,1,3,5)'
839 0
839 0
840 $ log 'ancestor(1,2,3,4,5)'
840 $ log 'ancestor(1,2,3,4,5)'
841 1
841 1
842
842
843 test ancestors
843 test ancestors
844
844
845 $ log 'ancestors(5)'
845 $ log 'ancestors(5)'
846 0
846 0
847 1
847 1
848 3
848 3
849 5
849 5
850 $ log 'ancestor(ancestors(5))'
850 $ log 'ancestor(ancestors(5))'
851 0
851 0
852 $ log '::r3232()'
852 $ log '::r3232()'
853 0
853 0
854 1
854 1
855 2
855 2
856 3
856 3
857
857
858 $ log 'author(bob)'
858 $ log 'author(bob)'
859 2
859 2
860 $ log 'author("re:bob|test")'
860 $ log 'author("re:bob|test")'
861 0
861 0
862 1
862 1
863 2
863 2
864 3
864 3
865 4
865 4
866 5
866 5
867 6
867 6
868 7
868 7
869 8
869 8
870 9
870 9
871 $ log 'author(r"re:\S")'
871 $ log 'author(r"re:\S")'
872 0
872 0
873 1
873 1
874 2
874 2
875 3
875 3
876 4
876 4
877 5
877 5
878 6
878 6
879 7
879 7
880 8
880 8
881 9
881 9
882 $ log 'branch(é)'
882 $ log 'branch(é)'
883 8
883 8
884 9
884 9
885 $ log 'branch(a)'
885 $ log 'branch(a)'
886 0
886 0
887 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
887 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
888 0 a
888 0 a
889 2 a-b-c-
889 2 a-b-c-
890 3 +a+b+c+
890 3 +a+b+c+
891 4 -a-b-c-
891 4 -a-b-c-
892 5 !a/b/c/
892 5 !a/b/c/
893 6 _a_b_c_
893 6 _a_b_c_
894 7 .a.b.c.
894 7 .a.b.c.
895 $ log 'children(ancestor(4,5))'
895 $ log 'children(ancestor(4,5))'
896 2
896 2
897 3
897 3
898
898
899 $ log 'children(4)'
899 $ log 'children(4)'
900 6
900 6
901 8
901 8
902 $ log 'children(null)'
902 $ log 'children(null)'
903 0
903 0
904
904
905 $ log 'closed()'
905 $ log 'closed()'
906 $ log 'contains(a)'
906 $ log 'contains(a)'
907 0
907 0
908 1
908 1
909 3
909 3
910 5
910 5
911 $ log 'contains("../repo/a")'
911 $ log 'contains("../repo/a")'
912 0
912 0
913 1
913 1
914 3
914 3
915 5
915 5
916 $ log 'desc(B)'
916 $ log 'desc(B)'
917 5
917 5
918 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
918 $ hg log -r 'desc(r"re:S?u")' --template "{rev} {desc|firstline}\n"
919 5 5 bug
919 5 5 bug
920 6 6 issue619
920 6 6 issue619
921 $ log 'descendants(2 or 3)'
921 $ log 'descendants(2 or 3)'
922 2
922 2
923 3
923 3
924 4
924 4
925 5
925 5
926 6
926 6
927 7
927 7
928 8
928 8
929 9
929 9
930 $ log 'file("b*")'
930 $ log 'file("b*")'
931 1
931 1
932 4
932 4
933 $ log 'filelog("b")'
933 $ log 'filelog("b")'
934 1
934 1
935 4
935 4
936 $ log 'filelog("../repo/b")'
936 $ log 'filelog("../repo/b")'
937 1
937 1
938 4
938 4
939 $ log 'follow()'
939 $ log 'follow()'
940 0
940 0
941 1
941 1
942 2
942 2
943 4
943 4
944 8
944 8
945 9
945 9
946 $ log 'grep("issue\d+")'
946 $ log 'grep("issue\d+")'
947 6
947 6
948 $ try 'grep("(")' # invalid regular expression
948 $ try 'grep("(")' # invalid regular expression
949 (func
949 (func
950 ('symbol', 'grep')
950 ('symbol', 'grep')
951 ('string', '('))
951 ('string', '('))
952 hg: parse error: invalid match pattern: unbalanced parenthesis
952 hg: parse error: invalid match pattern: unbalanced parenthesis
953 [255]
953 [255]
954 $ try 'grep("\bissue\d+")'
954 $ try 'grep("\bissue\d+")'
955 (func
955 (func
956 ('symbol', 'grep')
956 ('symbol', 'grep')
957 ('string', '\x08issue\\d+'))
957 ('string', '\x08issue\\d+'))
958 * set:
958 * set:
959 <filteredset
959 <filteredset
960 <fullreposet+ 0:9>,
960 <fullreposet+ 0:9>,
961 <grep '\x08issue\\d+'>>
961 <grep '\x08issue\\d+'>>
962 $ try 'grep(r"\bissue\d+")'
962 $ try 'grep(r"\bissue\d+")'
963 (func
963 (func
964 ('symbol', 'grep')
964 ('symbol', 'grep')
965 ('string', '\\bissue\\d+'))
965 ('string', '\\bissue\\d+'))
966 * set:
966 * set:
967 <filteredset
967 <filteredset
968 <fullreposet+ 0:9>,
968 <fullreposet+ 0:9>,
969 <grep '\\bissue\\d+'>>
969 <grep '\\bissue\\d+'>>
970 6
970 6
971 $ try 'grep(r"\")'
971 $ try 'grep(r"\")'
972 hg: parse error at 7: unterminated string
972 hg: parse error at 7: unterminated string
973 [255]
973 [255]
974 $ log 'head()'
974 $ log 'head()'
975 0
975 0
976 1
976 1
977 2
977 2
978 3
978 3
979 4
979 4
980 5
980 5
981 6
981 6
982 7
982 7
983 9
983 9
984 $ log 'heads(6::)'
984 $ log 'heads(6::)'
985 7
985 7
986 $ log 'keyword(issue)'
986 $ log 'keyword(issue)'
987 6
987 6
988 $ log 'keyword("test a")'
988 $ log 'keyword("test a")'
989 $ log 'limit(head(), 1)'
989 $ log 'limit(head(), 1)'
990 0
990 0
991 $ log 'limit(author("re:bob|test"), 3, 5)'
991 $ log 'limit(author("re:bob|test"), 3, 5)'
992 5
992 5
993 6
993 6
994 7
994 7
995 $ log 'limit(author("re:bob|test"), offset=6)'
995 $ log 'limit(author("re:bob|test"), offset=6)'
996 6
996 6
997 $ log 'limit(author("re:bob|test"), offset=10)'
997 $ log 'limit(author("re:bob|test"), offset=10)'
998 $ log 'limit(all(), 1, -1)'
998 $ log 'limit(all(), 1, -1)'
999 hg: parse error: negative offset
999 hg: parse error: negative offset
1000 [255]
1000 [255]
1001 $ log 'matching(6)'
1001 $ log 'matching(6)'
1002 6
1002 6
1003 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1003 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
1004 6
1004 6
1005 7
1005 7
1006
1006
1007 Testing min and max
1007 Testing min and max
1008
1008
1009 max: simple
1009 max: simple
1010
1010
1011 $ log 'max(contains(a))'
1011 $ log 'max(contains(a))'
1012 5
1012 5
1013
1013
1014 max: simple on unordered set)
1014 max: simple on unordered set)
1015
1015
1016 $ log 'max((4+0+2+5+7) and contains(a))'
1016 $ log 'max((4+0+2+5+7) and contains(a))'
1017 5
1017 5
1018
1018
1019 max: no result
1019 max: no result
1020
1020
1021 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1021 $ log 'max(contains(stringthatdoesnotappearanywhere))'
1022
1022
1023 max: no result on unordered set
1023 max: no result on unordered set
1024
1024
1025 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1025 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1026
1026
1027 min: simple
1027 min: simple
1028
1028
1029 $ log 'min(contains(a))'
1029 $ log 'min(contains(a))'
1030 0
1030 0
1031
1031
1032 min: simple on unordered set
1032 min: simple on unordered set
1033
1033
1034 $ log 'min((4+0+2+5+7) and contains(a))'
1034 $ log 'min((4+0+2+5+7) and contains(a))'
1035 0
1035 0
1036
1036
1037 min: empty
1037 min: empty
1038
1038
1039 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1039 $ log 'min(contains(stringthatdoesnotappearanywhere))'
1040
1040
1041 min: empty on unordered set
1041 min: empty on unordered set
1042
1042
1043 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1043 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
1044
1044
1045
1045
1046 $ log 'merge()'
1046 $ log 'merge()'
1047 6
1047 6
1048 $ log 'branchpoint()'
1048 $ log 'branchpoint()'
1049 1
1049 1
1050 4
1050 4
1051 $ log 'modifies(b)'
1051 $ log 'modifies(b)'
1052 4
1052 4
1053 $ log 'modifies("path:b")'
1053 $ log 'modifies("path:b")'
1054 4
1054 4
1055 $ log 'modifies("*")'
1055 $ log 'modifies("*")'
1056 4
1056 4
1057 6
1057 6
1058 $ log 'modifies("set:modified()")'
1058 $ log 'modifies("set:modified()")'
1059 4
1059 4
1060 $ log 'id(5)'
1060 $ log 'id(5)'
1061 2
1061 2
1062 $ log 'only(9)'
1062 $ log 'only(9)'
1063 8
1063 8
1064 9
1064 9
1065 $ log 'only(8)'
1065 $ log 'only(8)'
1066 8
1066 8
1067 $ log 'only(9, 5)'
1067 $ log 'only(9, 5)'
1068 2
1068 2
1069 4
1069 4
1070 8
1070 8
1071 9
1071 9
1072 $ log 'only(7 + 9, 5 + 2)'
1072 $ log 'only(7 + 9, 5 + 2)'
1073 4
1073 4
1074 6
1074 6
1075 7
1075 7
1076 8
1076 8
1077 9
1077 9
1078
1078
1079 Test empty set input
1079 Test empty set input
1080 $ log 'only(p2())'
1080 $ log 'only(p2())'
1081 $ log 'only(p1(), p2())'
1081 $ log 'only(p1(), p2())'
1082 0
1082 0
1083 1
1083 1
1084 2
1084 2
1085 4
1085 4
1086 8
1086 8
1087 9
1087 9
1088
1088
1089 Test '%' operator
1089 Test '%' operator
1090
1090
1091 $ log '9%'
1091 $ log '9%'
1092 8
1092 8
1093 9
1093 9
1094 $ log '9%5'
1094 $ log '9%5'
1095 2
1095 2
1096 4
1096 4
1097 8
1097 8
1098 9
1098 9
1099 $ log '(7 + 9)%(5 + 2)'
1099 $ log '(7 + 9)%(5 + 2)'
1100 4
1100 4
1101 6
1101 6
1102 7
1102 7
1103 8
1103 8
1104 9
1104 9
1105
1105
1106 Test operand of '%' is optimized recursively (issue4670)
1106 Test operand of '%' is optimized recursively (issue4670)
1107
1107
1108 $ try --optimize '8:9-8%'
1108 $ try --optimize '8:9-8%'
1109 (onlypost
1109 (onlypost
1110 (minus
1110 (minus
1111 (range
1111 (range
1112 ('symbol', '8')
1112 ('symbol', '8')
1113 ('symbol', '9'))
1113 ('symbol', '9'))
1114 ('symbol', '8')))
1114 ('symbol', '8')))
1115 * optimized:
1115 * optimized:
1116 (func
1116 (func
1117 ('symbol', 'only')
1117 ('symbol', 'only')
1118 (difference
1118 (difference
1119 (range
1119 (range
1120 ('symbol', '8')
1120 ('symbol', '8')
1121 ('symbol', '9')
1121 ('symbol', '9')
1122 define)
1122 define)
1123 ('symbol', '8')
1123 ('symbol', '8')
1124 define)
1124 define)
1125 define)
1125 define)
1126 * set:
1126 * set:
1127 <baseset+ [8, 9]>
1127 <baseset+ [8, 9]>
1128 8
1128 8
1129 9
1129 9
1130 $ try --optimize '(9)%(5)'
1130 $ try --optimize '(9)%(5)'
1131 (only
1131 (only
1132 (group
1132 (group
1133 ('symbol', '9'))
1133 ('symbol', '9'))
1134 (group
1134 (group
1135 ('symbol', '5')))
1135 ('symbol', '5')))
1136 * optimized:
1136 * optimized:
1137 (func
1137 (func
1138 ('symbol', 'only')
1138 ('symbol', 'only')
1139 (list
1139 (list
1140 ('symbol', '9')
1140 ('symbol', '9')
1141 ('symbol', '5'))
1141 ('symbol', '5'))
1142 define)
1142 define)
1143 * set:
1143 * set:
1144 <baseset+ [2, 4, 8, 9]>
1144 <baseset+ [2, 4, 8, 9]>
1145 2
1145 2
1146 4
1146 4
1147 8
1147 8
1148 9
1148 9
1149
1149
1150 Test the order of operations
1150 Test the order of operations
1151
1151
1152 $ log '7 + 9%5 + 2'
1152 $ log '7 + 9%5 + 2'
1153 7
1153 7
1154 2
1154 2
1155 4
1155 4
1156 8
1156 8
1157 9
1157 9
1158
1158
1159 Test explicit numeric revision
1159 Test explicit numeric revision
1160 $ log 'rev(-2)'
1160 $ log 'rev(-2)'
1161 $ log 'rev(-1)'
1161 $ log 'rev(-1)'
1162 -1
1162 -1
1163 $ log 'rev(0)'
1163 $ log 'rev(0)'
1164 0
1164 0
1165 $ log 'rev(9)'
1165 $ log 'rev(9)'
1166 9
1166 9
1167 $ log 'rev(10)'
1167 $ log 'rev(10)'
1168 $ log 'rev(tip)'
1168 $ log 'rev(tip)'
1169 hg: parse error: rev expects a number
1169 hg: parse error: rev expects a number
1170 [255]
1170 [255]
1171
1171
1172 Test hexadecimal revision
1172 Test hexadecimal revision
1173 $ log 'id(2)'
1173 $ log 'id(2)'
1174 abort: 00changelog.i@2: ambiguous identifier!
1174 abort: 00changelog.i@2: ambiguous identifier!
1175 [255]
1175 [255]
1176 $ log 'id(23268)'
1176 $ log 'id(23268)'
1177 4
1177 4
1178 $ log 'id(2785f51eece)'
1178 $ log 'id(2785f51eece)'
1179 0
1179 0
1180 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1180 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532c)'
1181 8
1181 8
1182 $ log 'id(d5d0dcbdc4a)'
1182 $ log 'id(d5d0dcbdc4a)'
1183 $ log 'id(d5d0dcbdc4w)'
1183 $ log 'id(d5d0dcbdc4w)'
1184 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1184 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532d)'
1185 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1185 $ log 'id(d5d0dcbdc4d9ff5dbb2d336f32f0bb561c1a532q)'
1186 $ log 'id(1.0)'
1186 $ log 'id(1.0)'
1187 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1187 $ log 'id(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)'
1188
1188
1189 Test null revision
1189 Test null revision
1190 $ log '(null)'
1190 $ log '(null)'
1191 -1
1191 -1
1192 $ log '(null:0)'
1192 $ log '(null:0)'
1193 -1
1193 -1
1194 0
1194 0
1195 $ log '(0:null)'
1195 $ log '(0:null)'
1196 0
1196 0
1197 -1
1197 -1
1198 $ log 'null::0'
1198 $ log 'null::0'
1199 -1
1199 -1
1200 0
1200 0
1201 $ log 'null:tip - 0:'
1201 $ log 'null:tip - 0:'
1202 -1
1202 -1
1203 $ log 'null: and null::' | head -1
1203 $ log 'null: and null::' | head -1
1204 -1
1204 -1
1205 $ log 'null: or 0:' | head -2
1205 $ log 'null: or 0:' | head -2
1206 -1
1206 -1
1207 0
1207 0
1208 $ log 'ancestors(null)'
1208 $ log 'ancestors(null)'
1209 -1
1209 -1
1210 $ log 'reverse(null:)' | tail -2
1210 $ log 'reverse(null:)' | tail -2
1211 0
1211 0
1212 -1
1212 -1
1213 BROKEN: should be '-1'
1213 BROKEN: should be '-1'
1214 $ log 'first(null:)'
1214 $ log 'first(null:)'
1215 BROKEN: should be '-1'
1215 BROKEN: should be '-1'
1216 $ log 'min(null:)'
1216 $ log 'min(null:)'
1217 $ log 'tip:null and all()' | tail -2
1217 $ log 'tip:null and all()' | tail -2
1218 1
1218 1
1219 0
1219 0
1220
1220
1221 Test working-directory revision
1221 Test working-directory revision
1222 $ hg debugrevspec 'wdir()'
1222 $ hg debugrevspec 'wdir()'
1223 2147483647
1223 2147483647
1224 $ hg debugrevspec 'wdir()^'
1224 $ hg debugrevspec 'wdir()^'
1225 9
1225 9
1226 $ hg up 7
1226 $ hg up 7
1227 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1227 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1228 $ hg debugrevspec 'wdir()^'
1228 $ hg debugrevspec 'wdir()^'
1229 7
1229 7
1230 $ hg debugrevspec 'wdir()^0'
1230 $ hg debugrevspec 'wdir()^0'
1231 2147483647
1231 2147483647
1232 $ hg debugrevspec 'wdir()~3'
1232 $ hg debugrevspec 'wdir()~3'
1233 5
1233 5
1234 $ hg debugrevspec 'ancestors(wdir())'
1234 $ hg debugrevspec 'ancestors(wdir())'
1235 0
1235 0
1236 1
1236 1
1237 2
1237 2
1238 3
1238 3
1239 4
1239 4
1240 5
1240 5
1241 6
1241 6
1242 7
1242 7
1243 2147483647
1243 2147483647
1244 $ hg debugrevspec 'wdir()~0'
1244 $ hg debugrevspec 'wdir()~0'
1245 2147483647
1245 2147483647
1246 $ hg debugrevspec 'p1(wdir())'
1246 $ hg debugrevspec 'p1(wdir())'
1247 7
1247 7
1248 $ hg debugrevspec 'p2(wdir())'
1248 $ hg debugrevspec 'p2(wdir())'
1249 $ hg debugrevspec 'parents(wdir())'
1249 $ hg debugrevspec 'parents(wdir())'
1250 7
1250 7
1251 $ hg debugrevspec 'wdir()^1'
1251 $ hg debugrevspec 'wdir()^1'
1252 7
1252 7
1253 $ hg debugrevspec 'wdir()^2'
1253 $ hg debugrevspec 'wdir()^2'
1254 $ hg debugrevspec 'wdir()^3'
1254 $ hg debugrevspec 'wdir()^3'
1255 hg: parse error: ^ expects a number 0, 1, or 2
1255 hg: parse error: ^ expects a number 0, 1, or 2
1256 [255]
1256 [255]
1257 For tests consistency
1257 For tests consistency
1258 $ hg up 9
1258 $ hg up 9
1259 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1259 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1260 $ hg debugrevspec 'tip or wdir()'
1260 $ hg debugrevspec 'tip or wdir()'
1261 9
1261 9
1262 2147483647
1262 2147483647
1263 $ hg debugrevspec '0:tip and wdir()'
1263 $ hg debugrevspec '0:tip and wdir()'
1264 $ log '0:wdir()' | tail -3
1264 $ log '0:wdir()' | tail -3
1265 8
1265 8
1266 9
1266 9
1267 2147483647
1267 2147483647
1268 $ log 'wdir():0' | head -3
1268 $ log 'wdir():0' | head -3
1269 2147483647
1269 2147483647
1270 9
1270 9
1271 8
1271 8
1272 $ log 'wdir():wdir()'
1272 $ log 'wdir():wdir()'
1273 2147483647
1273 2147483647
1274 $ log '(all() + wdir()) & min(. + wdir())'
1274 $ log '(all() + wdir()) & min(. + wdir())'
1275 9
1275 9
1276 $ log '(all() + wdir()) & max(. + wdir())'
1276 $ log '(all() + wdir()) & max(. + wdir())'
1277 2147483647
1277 2147483647
1278 $ log '(all() + wdir()) & first(wdir() + .)'
1278 $ log '(all() + wdir()) & first(wdir() + .)'
1279 2147483647
1279 2147483647
1280 $ log '(all() + wdir()) & last(. + wdir())'
1280 $ log '(all() + wdir()) & last(. + wdir())'
1281 2147483647
1281 2147483647
1282
1282
1283 Test working-directory integer revision and node id
1283 Test working-directory integer revision and node id
1284 (BUG: '0:wdir()' is still needed to populate wdir revision)
1284 (BUG: '0:wdir()' is still needed to populate wdir revision)
1285
1285
1286 $ hg debugrevspec '0:wdir() & 2147483647'
1286 $ hg debugrevspec '0:wdir() & 2147483647'
1287 2147483647
1287 2147483647
1288 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1288 $ hg debugrevspec '0:wdir() & rev(2147483647)'
1289 2147483647
1289 2147483647
1290 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1290 $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
1291 2147483647
1291 2147483647
1292 $ hg debugrevspec '0:wdir() & ffffffffffff'
1292 $ hg debugrevspec '0:wdir() & ffffffffffff'
1293 2147483647
1293 2147483647
1294 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1294 $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
1295 2147483647
1295 2147483647
1296 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1296 $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
1297 2147483647
1297 2147483647
1298
1298
1299 $ cd ..
1299 $ cd ..
1300
1300
1301 Test short 'ff...' hash collision
1301 Test short 'ff...' hash collision
1302 (BUG: '0:wdir()' is still needed to populate wdir revision)
1302 (BUG: '0:wdir()' is still needed to populate wdir revision)
1303
1303
1304 $ hg init wdir-hashcollision
1304 $ hg init wdir-hashcollision
1305 $ cd wdir-hashcollision
1305 $ cd wdir-hashcollision
1306 $ cat <<EOF >> .hg/hgrc
1306 $ cat <<EOF >> .hg/hgrc
1307 > [experimental]
1307 > [experimental]
1308 > evolution = createmarkers
1308 > evolution = createmarkers
1309 > EOF
1309 > EOF
1310 $ echo 0 > a
1310 $ echo 0 > a
1311 $ hg ci -qAm 0
1311 $ hg ci -qAm 0
1312 $ for i in 2463 2961 6726 78127; do
1312 $ for i in 2463 2961 6726 78127; do
1313 > hg up -q 0
1313 > hg up -q 0
1314 > echo $i > a
1314 > echo $i > a
1315 > hg ci -qm $i
1315 > hg ci -qm $i
1316 > done
1316 > done
1317 $ hg up -q null
1317 $ hg up -q null
1318 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1318 $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
1319 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1319 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
1320 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1320 1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
1321 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1321 2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
1322 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1322 3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
1323 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1323 4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
1324 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1324 2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
1325 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1325 $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
1326
1326
1327 $ hg debugrevspec '0:wdir() & fff'
1327 $ hg debugrevspec '0:wdir() & fff'
1328 abort: 00changelog.i@fff: ambiguous identifier!
1328 abort: 00changelog.i@fff: ambiguous identifier!
1329 [255]
1329 [255]
1330 $ hg debugrevspec '0:wdir() & ffff'
1330 $ hg debugrevspec '0:wdir() & ffff'
1331 abort: 00changelog.i@ffff: ambiguous identifier!
1331 abort: 00changelog.i@ffff: ambiguous identifier!
1332 [255]
1332 [255]
1333 $ hg debugrevspec '0:wdir() & fffb'
1333 $ hg debugrevspec '0:wdir() & fffb'
1334 abort: 00changelog.i@fffb: ambiguous identifier!
1334 abort: 00changelog.i@fffb: ambiguous identifier!
1335 [255]
1335 [255]
1336 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1336 BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
1337 $ hg debugrevspec '0:wdir() & id(fffb)'
1337 $ hg debugrevspec '0:wdir() & id(fffb)'
1338 2
1338 2
1339 $ hg debugrevspec '0:wdir() & ffff8'
1339 $ hg debugrevspec '0:wdir() & ffff8'
1340 4
1340 4
1341 $ hg debugrevspec '0:wdir() & fffff'
1341 $ hg debugrevspec '0:wdir() & fffff'
1342 2147483647
1342 2147483647
1343
1343
1344 $ cd ..
1344 $ cd ..
1345
1345
1346 Test branch() with wdir()
1346 Test branch() with wdir()
1347
1347
1348 $ cd repo
1348 $ cd repo
1349
1349
1350 $ log '0:wdir() & branch("literal")'
1350 $ log '0:wdir() & branch("literal")'
1351 8
1351 8
1352 9
1352 9
1353 2147483647
1353 2147483647
1354 $ log '0:wdir() & branch("re")'
1354 $ log '0:wdir() & branch("re")'
1355 8
1355 8
1356 9
1356 9
1357 2147483647
1357 2147483647
1358 $ log '0:wdir() & branch("re:^a")'
1358 $ log '0:wdir() & branch("re:^a")'
1359 0
1359 0
1360 2
1360 2
1361 $ log '0:wdir() & branch(8)'
1361 $ log '0:wdir() & branch(8)'
1362 8
1362 8
1363 9
1363 9
1364 2147483647
1364 2147483647
1365
1365
1366 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1366 branch(wdir()) returns all revisions belonging to the working branch. The wdir
1367 itself isn't returned unless it is explicitly populated.
1367 itself isn't returned unless it is explicitly populated.
1368
1368
1369 $ log 'branch(wdir())'
1369 $ log 'branch(wdir())'
1370 8
1370 8
1371 9
1371 9
1372 $ log '0:wdir() & branch(wdir())'
1372 $ log '0:wdir() & branch(wdir())'
1373 8
1373 8
1374 9
1374 9
1375 2147483647
1375 2147483647
1376
1376
1377 $ log 'outgoing()'
1377 $ log 'outgoing()'
1378 8
1378 8
1379 9
1379 9
1380 $ log 'outgoing("../remote1")'
1380 $ log 'outgoing("../remote1")'
1381 8
1381 8
1382 9
1382 9
1383 $ log 'outgoing("../remote2")'
1383 $ log 'outgoing("../remote2")'
1384 3
1384 3
1385 5
1385 5
1386 6
1386 6
1387 7
1387 7
1388 9
1388 9
1389 $ log 'p1(merge())'
1389 $ log 'p1(merge())'
1390 5
1390 5
1391 $ log 'p2(merge())'
1391 $ log 'p2(merge())'
1392 4
1392 4
1393 $ log 'parents(merge())'
1393 $ log 'parents(merge())'
1394 4
1394 4
1395 5
1395 5
1396 $ log 'p1(branchpoint())'
1396 $ log 'p1(branchpoint())'
1397 0
1397 0
1398 2
1398 2
1399 $ log 'p2(branchpoint())'
1399 $ log 'p2(branchpoint())'
1400 $ log 'parents(branchpoint())'
1400 $ log 'parents(branchpoint())'
1401 0
1401 0
1402 2
1402 2
1403 $ log 'removes(a)'
1403 $ log 'removes(a)'
1404 2
1404 2
1405 6
1405 6
1406 $ log 'roots(all())'
1406 $ log 'roots(all())'
1407 0
1407 0
1408 $ log 'reverse(2 or 3 or 4 or 5)'
1408 $ log 'reverse(2 or 3 or 4 or 5)'
1409 5
1409 5
1410 4
1410 4
1411 3
1411 3
1412 2
1412 2
1413 $ log 'reverse(all())'
1413 $ log 'reverse(all())'
1414 9
1414 9
1415 8
1415 8
1416 7
1416 7
1417 6
1417 6
1418 5
1418 5
1419 4
1419 4
1420 3
1420 3
1421 2
1421 2
1422 1
1422 1
1423 0
1423 0
1424 $ log 'reverse(all()) & filelog(b)'
1424 $ log 'reverse(all()) & filelog(b)'
1425 4
1425 4
1426 1
1426 1
1427 $ log 'rev(5)'
1427 $ log 'rev(5)'
1428 5
1428 5
1429 $ log 'sort(limit(reverse(all()), 3))'
1429 $ log 'sort(limit(reverse(all()), 3))'
1430 7
1430 7
1431 8
1431 8
1432 9
1432 9
1433 $ log 'sort(2 or 3 or 4 or 5, date)'
1433 $ log 'sort(2 or 3 or 4 or 5, date)'
1434 2
1434 2
1435 3
1435 3
1436 5
1436 5
1437 4
1437 4
1438 $ log 'tagged()'
1438 $ log 'tagged()'
1439 6
1439 6
1440 $ log 'tag()'
1440 $ log 'tag()'
1441 6
1441 6
1442 $ log 'tag(1.0)'
1442 $ log 'tag(1.0)'
1443 6
1443 6
1444 $ log 'tag(tip)'
1444 $ log 'tag(tip)'
1445 9
1445 9
1446
1446
1447 Test order of revisions in compound expression
1447 Test order of revisions in compound expression
1448 ----------------------------------------------
1448 ----------------------------------------------
1449
1449
1450 The general rule is that only the outermost (= leftmost) predicate can
1450 The general rule is that only the outermost (= leftmost) predicate can
1451 enforce its ordering requirement. The other predicates should take the
1451 enforce its ordering requirement. The other predicates should take the
1452 ordering defined by it.
1452 ordering defined by it.
1453
1453
1454 'A & B' should follow the order of 'A':
1454 'A & B' should follow the order of 'A':
1455
1455
1456 $ log '2:0 & 0::2'
1456 $ log '2:0 & 0::2'
1457 2
1457 2
1458 1
1458 1
1459 0
1459 0
1460
1460
1461 'head()' combines sets in right order:
1461 'head()' combines sets in right order:
1462
1462
1463 $ log '2:0 & head()'
1463 $ log '2:0 & head()'
1464 2
1464 2
1465 1
1465 1
1466 0
1466 0
1467
1467
1468 'x:y' takes ordering parameter into account:
1468 'x:y' takes ordering parameter into account:
1469
1469
1470 $ try -p optimized '3:0 & 0:3 & not 2:1'
1470 $ try -p optimized '3:0 & 0:3 & not 2:1'
1471 * optimized:
1471 * optimized:
1472 (difference
1472 (difference
1473 (and
1473 (and
1474 (range
1474 (range
1475 ('symbol', '3')
1475 ('symbol', '3')
1476 ('symbol', '0')
1476 ('symbol', '0')
1477 define)
1477 define)
1478 (range
1478 (range
1479 ('symbol', '0')
1479 ('symbol', '0')
1480 ('symbol', '3')
1480 ('symbol', '3')
1481 follow)
1481 follow)
1482 define)
1482 define)
1483 (range
1483 (range
1484 ('symbol', '2')
1484 ('symbol', '2')
1485 ('symbol', '1')
1485 ('symbol', '1')
1486 any)
1486 any)
1487 define)
1487 define)
1488 * set:
1488 * set:
1489 <filteredset
1489 <filteredset
1490 <filteredset
1490 <filteredset
1491 <spanset- 0:3>,
1491 <spanset- 0:3>,
1492 <spanset+ 0:3>>,
1492 <spanset+ 0:3>>,
1493 <not
1493 <not
1494 <spanset+ 1:2>>>
1494 <spanset+ 1:2>>>
1495 3
1495 3
1496 0
1496 0
1497
1497
1498 'a + b', which is optimized to '_list(a b)', should take the ordering of
1498 'a + b', which is optimized to '_list(a b)', should take the ordering of
1499 the left expression:
1499 the left expression:
1500
1500
1501 $ try --optimize '2:0 & (0 + 1 + 2)'
1501 $ try --optimize '2:0 & (0 + 1 + 2)'
1502 (and
1502 (and
1503 (range
1503 (range
1504 ('symbol', '2')
1504 ('symbol', '2')
1505 ('symbol', '0'))
1505 ('symbol', '0'))
1506 (group
1506 (group
1507 (or
1507 (or
1508 (list
1508 (list
1509 ('symbol', '0')
1509 ('symbol', '0')
1510 ('symbol', '1')
1510 ('symbol', '1')
1511 ('symbol', '2')))))
1511 ('symbol', '2')))))
1512 * optimized:
1512 * optimized:
1513 (and
1513 (and
1514 (range
1514 (range
1515 ('symbol', '2')
1515 ('symbol', '2')
1516 ('symbol', '0')
1516 ('symbol', '0')
1517 define)
1517 define)
1518 (func
1518 (func
1519 ('symbol', '_list')
1519 ('symbol', '_list')
1520 ('string', '0\x001\x002')
1520 ('string', '0\x001\x002')
1521 follow)
1521 follow)
1522 define)
1522 define)
1523 * set:
1523 * set:
1524 <filteredset
1524 <filteredset
1525 <spanset- 0:2>,
1525 <spanset- 0:2>,
1526 <baseset [0, 1, 2]>>
1526 <baseset [0, 1, 2]>>
1527 2
1527 2
1528 1
1528 1
1529 0
1529 0
1530
1530
1531 'A + B' should take the ordering of the left expression:
1531 'A + B' should take the ordering of the left expression:
1532
1532
1533 $ try --optimize '2:0 & (0:1 + 2)'
1533 $ try --optimize '2:0 & (0:1 + 2)'
1534 (and
1534 (and
1535 (range
1535 (range
1536 ('symbol', '2')
1536 ('symbol', '2')
1537 ('symbol', '0'))
1537 ('symbol', '0'))
1538 (group
1538 (group
1539 (or
1539 (or
1540 (list
1540 (list
1541 (range
1541 (range
1542 ('symbol', '0')
1542 ('symbol', '0')
1543 ('symbol', '1'))
1543 ('symbol', '1'))
1544 ('symbol', '2')))))
1544 ('symbol', '2')))))
1545 * optimized:
1545 * optimized:
1546 (and
1546 (and
1547 (range
1547 (range
1548 ('symbol', '2')
1548 ('symbol', '2')
1549 ('symbol', '0')
1549 ('symbol', '0')
1550 define)
1550 define)
1551 (or
1551 (or
1552 (list
1552 (list
1553 ('symbol', '2')
1553 ('symbol', '2')
1554 (range
1554 (range
1555 ('symbol', '0')
1555 ('symbol', '0')
1556 ('symbol', '1')
1556 ('symbol', '1')
1557 follow))
1557 follow))
1558 follow)
1558 follow)
1559 define)
1559 define)
1560 * set:
1560 * set:
1561 <filteredset
1561 <filteredset
1562 <spanset- 0:2>,
1562 <spanset- 0:2>,
1563 <addset
1563 <addset
1564 <baseset [2]>,
1564 <baseset [2]>,
1565 <spanset+ 0:1>>>
1565 <spanset+ 0:1>>>
1566 2
1566 2
1567 1
1567 1
1568 0
1568 0
1569
1569
1570 '_intlist(a b)' should behave like 'a + b':
1570 '_intlist(a b)' should behave like 'a + b':
1571
1571
1572 $ trylist --optimize '2:0 & %ld' 0 1 2
1572 $ trylist --optimize '2:0 & %ld' 0 1 2
1573 (and
1573 (and
1574 (range
1574 (range
1575 ('symbol', '2')
1575 ('symbol', '2')
1576 ('symbol', '0'))
1576 ('symbol', '0'))
1577 (func
1577 (func
1578 ('symbol', '_intlist')
1578 ('symbol', '_intlist')
1579 ('string', '0\x001\x002')))
1579 ('string', '0\x001\x002')))
1580 * optimized:
1580 * optimized:
1581 (and
1581 (and
1582 (func
1582 (func
1583 ('symbol', '_intlist')
1583 ('symbol', '_intlist')
1584 ('string', '0\x001\x002')
1584 ('string', '0\x001\x002')
1585 follow)
1585 follow)
1586 (range
1586 (range
1587 ('symbol', '2')
1587 ('symbol', '2')
1588 ('symbol', '0')
1588 ('symbol', '0')
1589 define)
1589 define)
1590 define)
1590 define)
1591 * set:
1591 * set:
1592 <filteredset
1592 <filteredset
1593 <spanset- 0:2>,
1593 <spanset- 0:2>,
1594 <baseset+ [0, 1, 2]>>
1594 <baseset+ [0, 1, 2]>>
1595 2
1595 2
1596 1
1596 1
1597 0
1597 0
1598
1598
1599 $ trylist --optimize '%ld & 2:0' 0 2 1
1599 $ trylist --optimize '%ld & 2:0' 0 2 1
1600 (and
1600 (and
1601 (func
1601 (func
1602 ('symbol', '_intlist')
1602 ('symbol', '_intlist')
1603 ('string', '0\x002\x001'))
1603 ('string', '0\x002\x001'))
1604 (range
1604 (range
1605 ('symbol', '2')
1605 ('symbol', '2')
1606 ('symbol', '0')))
1606 ('symbol', '0')))
1607 * optimized:
1607 * optimized:
1608 (and
1608 (and
1609 (func
1609 (func
1610 ('symbol', '_intlist')
1610 ('symbol', '_intlist')
1611 ('string', '0\x002\x001')
1611 ('string', '0\x002\x001')
1612 define)
1612 define)
1613 (range
1613 (range
1614 ('symbol', '2')
1614 ('symbol', '2')
1615 ('symbol', '0')
1615 ('symbol', '0')
1616 follow)
1616 follow)
1617 define)
1617 define)
1618 * set:
1618 * set:
1619 <filteredset
1619 <filteredset
1620 <baseset [0, 2, 1]>,
1620 <baseset [0, 2, 1]>,
1621 <spanset- 0:2>>
1621 <spanset- 0:2>>
1622 0
1622 0
1623 2
1623 2
1624 1
1624 1
1625
1625
1626 '_hexlist(a b)' should behave like 'a + b':
1626 '_hexlist(a b)' should behave like 'a + b':
1627
1627
1628 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1628 $ trylist --optimize --bin '2:0 & %ln' `hg log -T '{node} ' -r0:2`
1629 (and
1629 (and
1630 (range
1630 (range
1631 ('symbol', '2')
1631 ('symbol', '2')
1632 ('symbol', '0'))
1632 ('symbol', '0'))
1633 (func
1633 (func
1634 ('symbol', '_hexlist')
1634 ('symbol', '_hexlist')
1635 ('string', '*'))) (glob)
1635 ('string', '*'))) (glob)
1636 * optimized:
1636 * optimized:
1637 (and
1637 (and
1638 (range
1638 (range
1639 ('symbol', '2')
1639 ('symbol', '2')
1640 ('symbol', '0')
1640 ('symbol', '0')
1641 define)
1641 define)
1642 (func
1642 (func
1643 ('symbol', '_hexlist')
1643 ('symbol', '_hexlist')
1644 ('string', '*') (glob)
1644 ('string', '*') (glob)
1645 follow)
1645 follow)
1646 define)
1646 define)
1647 * set:
1647 * set:
1648 <filteredset
1648 <filteredset
1649 <spanset- 0:2>,
1649 <spanset- 0:2>,
1650 <baseset [0, 1, 2]>>
1650 <baseset [0, 1, 2]>>
1651 2
1651 2
1652 1
1652 1
1653 0
1653 0
1654
1654
1655 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1655 $ trylist --optimize --bin '%ln & 2:0' `hg log -T '{node} ' -r0+2+1`
1656 (and
1656 (and
1657 (func
1657 (func
1658 ('symbol', '_hexlist')
1658 ('symbol', '_hexlist')
1659 ('string', '*')) (glob)
1659 ('string', '*')) (glob)
1660 (range
1660 (range
1661 ('symbol', '2')
1661 ('symbol', '2')
1662 ('symbol', '0')))
1662 ('symbol', '0')))
1663 * optimized:
1663 * optimized:
1664 (and
1664 (and
1665 (range
1665 (range
1666 ('symbol', '2')
1666 ('symbol', '2')
1667 ('symbol', '0')
1667 ('symbol', '0')
1668 follow)
1668 follow)
1669 (func
1669 (func
1670 ('symbol', '_hexlist')
1670 ('symbol', '_hexlist')
1671 ('string', '*') (glob)
1671 ('string', '*') (glob)
1672 define)
1672 define)
1673 define)
1673 define)
1674 * set:
1674 * set:
1675 <baseset [0, 2, 1]>
1675 <baseset [0, 2, 1]>
1676 0
1676 0
1677 2
1677 2
1678 1
1678 1
1679
1679
1680 '_list' should not go through the slow follow-order path if order doesn't
1680 '_list' should not go through the slow follow-order path if order doesn't
1681 matter:
1681 matter:
1682
1682
1683 $ try -p optimized '2:0 & not (0 + 1)'
1683 $ try -p optimized '2:0 & not (0 + 1)'
1684 * optimized:
1684 * optimized:
1685 (difference
1685 (difference
1686 (range
1686 (range
1687 ('symbol', '2')
1687 ('symbol', '2')
1688 ('symbol', '0')
1688 ('symbol', '0')
1689 define)
1689 define)
1690 (func
1690 (func
1691 ('symbol', '_list')
1691 ('symbol', '_list')
1692 ('string', '0\x001')
1692 ('string', '0\x001')
1693 any)
1693 any)
1694 define)
1694 define)
1695 * set:
1695 * set:
1696 <filteredset
1696 <filteredset
1697 <spanset- 0:2>,
1697 <spanset- 0:2>,
1698 <not
1698 <not
1699 <baseset [0, 1]>>>
1699 <baseset [0, 1]>>>
1700 2
1700 2
1701
1701
1702 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1702 $ try -p optimized '2:0 & not (0:2 & (0 + 1))'
1703 * optimized:
1703 * optimized:
1704 (difference
1704 (difference
1705 (range
1705 (range
1706 ('symbol', '2')
1706 ('symbol', '2')
1707 ('symbol', '0')
1707 ('symbol', '0')
1708 define)
1708 define)
1709 (and
1709 (and
1710 (range
1710 (range
1711 ('symbol', '0')
1711 ('symbol', '0')
1712 ('symbol', '2')
1712 ('symbol', '2')
1713 any)
1713 any)
1714 (func
1714 (func
1715 ('symbol', '_list')
1715 ('symbol', '_list')
1716 ('string', '0\x001')
1716 ('string', '0\x001')
1717 any)
1717 any)
1718 any)
1718 any)
1719 define)
1719 define)
1720 * set:
1720 * set:
1721 <filteredset
1721 <filteredset
1722 <spanset- 0:2>,
1722 <spanset- 0:2>,
1723 <not
1723 <not
1724 <baseset [0, 1]>>>
1724 <baseset [0, 1]>>>
1725 2
1725 2
1726
1726
1727 because 'present()' does nothing other than suppressing an error, the
1727 because 'present()' does nothing other than suppressing an error, the
1728 ordering requirement should be forwarded to the nested expression
1728 ordering requirement should be forwarded to the nested expression
1729
1729
1730 $ try -p optimized 'present(2 + 0 + 1)'
1730 $ try -p optimized 'present(2 + 0 + 1)'
1731 * optimized:
1731 * optimized:
1732 (func
1732 (func
1733 ('symbol', 'present')
1733 ('symbol', 'present')
1734 (func
1734 (func
1735 ('symbol', '_list')
1735 ('symbol', '_list')
1736 ('string', '2\x000\x001')
1736 ('string', '2\x000\x001')
1737 define)
1737 define)
1738 define)
1738 define)
1739 * set:
1739 * set:
1740 <baseset [2, 0, 1]>
1740 <baseset [2, 0, 1]>
1741 2
1741 2
1742 0
1742 0
1743 1
1743 1
1744
1744
1745 $ try --optimize '2:0 & present(0 + 1 + 2)'
1745 $ try --optimize '2:0 & present(0 + 1 + 2)'
1746 (and
1746 (and
1747 (range
1747 (range
1748 ('symbol', '2')
1748 ('symbol', '2')
1749 ('symbol', '0'))
1749 ('symbol', '0'))
1750 (func
1750 (func
1751 ('symbol', 'present')
1751 ('symbol', 'present')
1752 (or
1752 (or
1753 (list
1753 (list
1754 ('symbol', '0')
1754 ('symbol', '0')
1755 ('symbol', '1')
1755 ('symbol', '1')
1756 ('symbol', '2')))))
1756 ('symbol', '2')))))
1757 * optimized:
1757 * optimized:
1758 (and
1758 (and
1759 (range
1759 (range
1760 ('symbol', '2')
1760 ('symbol', '2')
1761 ('symbol', '0')
1761 ('symbol', '0')
1762 define)
1762 define)
1763 (func
1763 (func
1764 ('symbol', 'present')
1764 ('symbol', 'present')
1765 (func
1765 (func
1766 ('symbol', '_list')
1766 ('symbol', '_list')
1767 ('string', '0\x001\x002')
1767 ('string', '0\x001\x002')
1768 follow)
1768 follow)
1769 follow)
1769 follow)
1770 define)
1770 define)
1771 * set:
1771 * set:
1772 <filteredset
1772 <filteredset
1773 <spanset- 0:2>,
1773 <spanset- 0:2>,
1774 <baseset [0, 1, 2]>>
1774 <baseset [0, 1, 2]>>
1775 2
1775 2
1776 1
1776 1
1777 0
1777 0
1778
1778
1779 'reverse()' should take effect only if it is the outermost expression:
1779 'reverse()' should take effect only if it is the outermost expression:
1780
1780
1781 $ try --optimize '0:2 & reverse(all())'
1781 $ try --optimize '0:2 & reverse(all())'
1782 (and
1782 (and
1783 (range
1783 (range
1784 ('symbol', '0')
1784 ('symbol', '0')
1785 ('symbol', '2'))
1785 ('symbol', '2'))
1786 (func
1786 (func
1787 ('symbol', 'reverse')
1787 ('symbol', 'reverse')
1788 (func
1788 (func
1789 ('symbol', 'all')
1789 ('symbol', 'all')
1790 None)))
1790 None)))
1791 * optimized:
1791 * optimized:
1792 (and
1792 (and
1793 (range
1793 (range
1794 ('symbol', '0')
1794 ('symbol', '0')
1795 ('symbol', '2')
1795 ('symbol', '2')
1796 define)
1796 define)
1797 (func
1797 (func
1798 ('symbol', 'reverse')
1798 ('symbol', 'reverse')
1799 (func
1799 (func
1800 ('symbol', 'all')
1800 ('symbol', 'all')
1801 None
1801 None
1802 define)
1802 define)
1803 follow)
1803 follow)
1804 define)
1804 define)
1805 * set:
1805 * set:
1806 <filteredset
1806 <filteredset
1807 <spanset+ 0:2>,
1807 <spanset+ 0:2>,
1808 <spanset+ 0:9>>
1808 <spanset+ 0:9>>
1809 0
1809 0
1810 1
1810 1
1811 2
1811 2
1812
1812
1813 'sort()' should take effect only if it is the outermost expression:
1813 'sort()' should take effect only if it is the outermost expression:
1814
1814
1815 $ try --optimize '0:2 & sort(all(), -rev)'
1815 $ try --optimize '0:2 & sort(all(), -rev)'
1816 (and
1816 (and
1817 (range
1817 (range
1818 ('symbol', '0')
1818 ('symbol', '0')
1819 ('symbol', '2'))
1819 ('symbol', '2'))
1820 (func
1820 (func
1821 ('symbol', 'sort')
1821 ('symbol', 'sort')
1822 (list
1822 (list
1823 (func
1823 (func
1824 ('symbol', 'all')
1824 ('symbol', 'all')
1825 None)
1825 None)
1826 (negate
1826 (negate
1827 ('symbol', 'rev')))))
1827 ('symbol', 'rev')))))
1828 * optimized:
1828 * optimized:
1829 (and
1829 (and
1830 (range
1830 (range
1831 ('symbol', '0')
1831 ('symbol', '0')
1832 ('symbol', '2')
1832 ('symbol', '2')
1833 define)
1833 define)
1834 (func
1834 (func
1835 ('symbol', 'sort')
1835 ('symbol', 'sort')
1836 (list
1836 (list
1837 (func
1837 (func
1838 ('symbol', 'all')
1838 ('symbol', 'all')
1839 None
1839 None
1840 define)
1840 define)
1841 ('string', '-rev'))
1841 ('string', '-rev'))
1842 follow)
1842 follow)
1843 define)
1843 define)
1844 * set:
1844 * set:
1845 <filteredset
1845 <filteredset
1846 <spanset+ 0:2>,
1846 <spanset+ 0:2>,
1847 <spanset+ 0:9>>
1847 <spanset+ 0:9>>
1848 0
1848 0
1849 1
1849 1
1850 2
1850 2
1851
1851
1852 invalid argument passed to noop sort():
1852 invalid argument passed to noop sort():
1853
1853
1854 $ log '0:2 & sort()'
1854 $ log '0:2 & sort()'
1855 hg: parse error: sort requires one or two arguments
1855 hg: parse error: sort requires one or two arguments
1856 [255]
1856 [255]
1857 $ log '0:2 & sort(all(), -invalid)'
1857 $ log '0:2 & sort(all(), -invalid)'
1858 hg: parse error: unknown sort key '-invalid'
1858 hg: parse error: unknown sort key '-invalid'
1859 [255]
1859 [255]
1860
1860
1861 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1861 for 'A & f(B)', 'B' should not be affected by the order of 'A':
1862
1862
1863 $ try --optimize '2:0 & first(1 + 0 + 2)'
1863 $ try --optimize '2:0 & first(1 + 0 + 2)'
1864 (and
1864 (and
1865 (range
1865 (range
1866 ('symbol', '2')
1866 ('symbol', '2')
1867 ('symbol', '0'))
1867 ('symbol', '0'))
1868 (func
1868 (func
1869 ('symbol', 'first')
1869 ('symbol', 'first')
1870 (or
1870 (or
1871 (list
1871 (list
1872 ('symbol', '1')
1872 ('symbol', '1')
1873 ('symbol', '0')
1873 ('symbol', '0')
1874 ('symbol', '2')))))
1874 ('symbol', '2')))))
1875 * optimized:
1875 * optimized:
1876 (and
1876 (and
1877 (range
1877 (range
1878 ('symbol', '2')
1878 ('symbol', '2')
1879 ('symbol', '0')
1879 ('symbol', '0')
1880 define)
1880 define)
1881 (func
1881 (func
1882 ('symbol', 'first')
1882 ('symbol', 'first')
1883 (func
1883 (func
1884 ('symbol', '_list')
1884 ('symbol', '_list')
1885 ('string', '1\x000\x002')
1885 ('string', '1\x000\x002')
1886 define)
1886 define)
1887 follow)
1887 follow)
1888 define)
1888 define)
1889 * set:
1889 * set:
1890 <baseset
1890 <baseset
1891 <limit n=1, offset=0,
1891 <limit n=1, offset=0,
1892 <spanset- 0:2>,
1892 <spanset- 0:2>,
1893 <baseset [1, 0, 2]>>>
1893 <baseset [1, 0, 2]>>>
1894 1
1894 1
1895
1895
1896 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1896 $ try --optimize '2:0 & not last(0 + 2 + 1)'
1897 (and
1897 (and
1898 (range
1898 (range
1899 ('symbol', '2')
1899 ('symbol', '2')
1900 ('symbol', '0'))
1900 ('symbol', '0'))
1901 (not
1901 (not
1902 (func
1902 (func
1903 ('symbol', 'last')
1903 ('symbol', 'last')
1904 (or
1904 (or
1905 (list
1905 (list
1906 ('symbol', '0')
1906 ('symbol', '0')
1907 ('symbol', '2')
1907 ('symbol', '2')
1908 ('symbol', '1'))))))
1908 ('symbol', '1'))))))
1909 * optimized:
1909 * optimized:
1910 (difference
1910 (difference
1911 (range
1911 (range
1912 ('symbol', '2')
1912 ('symbol', '2')
1913 ('symbol', '0')
1913 ('symbol', '0')
1914 define)
1914 define)
1915 (func
1915 (func
1916 ('symbol', 'last')
1916 ('symbol', 'last')
1917 (func
1917 (func
1918 ('symbol', '_list')
1918 ('symbol', '_list')
1919 ('string', '0\x002\x001')
1919 ('string', '0\x002\x001')
1920 define)
1920 define)
1921 any)
1921 any)
1922 define)
1922 define)
1923 * set:
1923 * set:
1924 <filteredset
1924 <filteredset
1925 <spanset- 0:2>,
1925 <spanset- 0:2>,
1926 <not
1926 <not
1927 <baseset
1927 <baseset
1928 <last n=1,
1928 <last n=1,
1929 <fullreposet+ 0:9>,
1929 <fullreposet+ 0:9>,
1930 <baseset [1, 2, 0]>>>>>
1930 <baseset [1, 2, 0]>>>>>
1931 2
1931 2
1932 0
1932 0
1933
1933
1934 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1934 for 'A & (op)(B)', 'B' should not be affected by the order of 'A':
1935
1935
1936 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1936 $ try --optimize '2:0 & (1 + 0 + 2):(0 + 2 + 1)'
1937 (and
1937 (and
1938 (range
1938 (range
1939 ('symbol', '2')
1939 ('symbol', '2')
1940 ('symbol', '0'))
1940 ('symbol', '0'))
1941 (range
1941 (range
1942 (group
1942 (group
1943 (or
1943 (or
1944 (list
1944 (list
1945 ('symbol', '1')
1945 ('symbol', '1')
1946 ('symbol', '0')
1946 ('symbol', '0')
1947 ('symbol', '2'))))
1947 ('symbol', '2'))))
1948 (group
1948 (group
1949 (or
1949 (or
1950 (list
1950 (list
1951 ('symbol', '0')
1951 ('symbol', '0')
1952 ('symbol', '2')
1952 ('symbol', '2')
1953 ('symbol', '1'))))))
1953 ('symbol', '1'))))))
1954 * optimized:
1954 * optimized:
1955 (and
1955 (and
1956 (range
1956 (range
1957 ('symbol', '2')
1957 ('symbol', '2')
1958 ('symbol', '0')
1958 ('symbol', '0')
1959 define)
1959 define)
1960 (range
1960 (range
1961 (func
1961 (func
1962 ('symbol', '_list')
1962 ('symbol', '_list')
1963 ('string', '1\x000\x002')
1963 ('string', '1\x000\x002')
1964 define)
1964 define)
1965 (func
1965 (func
1966 ('symbol', '_list')
1966 ('symbol', '_list')
1967 ('string', '0\x002\x001')
1967 ('string', '0\x002\x001')
1968 define)
1968 define)
1969 follow)
1969 follow)
1970 define)
1970 define)
1971 * set:
1971 * set:
1972 <filteredset
1972 <filteredset
1973 <spanset- 0:2>,
1973 <spanset- 0:2>,
1974 <baseset [1]>>
1974 <baseset [1]>>
1975 1
1975 1
1976
1976
1977 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
1977 'A & B' can be rewritten as 'B & A' by weight, but that's fine as long as
1978 the ordering rule is determined before the rewrite; in this example,
1978 the ordering rule is determined before the rewrite; in this example,
1979 'B' follows the order of the initial set, which is the same order as 'A'
1979 'B' follows the order of the initial set, which is the same order as 'A'
1980 since 'A' also follows the order:
1980 since 'A' also follows the order:
1981
1981
1982 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1982 $ try --optimize 'contains("glob:*") & (2 + 0 + 1)'
1983 (and
1983 (and
1984 (func
1984 (func
1985 ('symbol', 'contains')
1985 ('symbol', 'contains')
1986 ('string', 'glob:*'))
1986 ('string', 'glob:*'))
1987 (group
1987 (group
1988 (or
1988 (or
1989 (list
1989 (list
1990 ('symbol', '2')
1990 ('symbol', '2')
1991 ('symbol', '0')
1991 ('symbol', '0')
1992 ('symbol', '1')))))
1992 ('symbol', '1')))))
1993 * optimized:
1993 * optimized:
1994 (and
1994 (and
1995 (func
1995 (func
1996 ('symbol', '_list')
1996 ('symbol', '_list')
1997 ('string', '2\x000\x001')
1997 ('string', '2\x000\x001')
1998 follow)
1998 follow)
1999 (func
1999 (func
2000 ('symbol', 'contains')
2000 ('symbol', 'contains')
2001 ('string', 'glob:*')
2001 ('string', 'glob:*')
2002 define)
2002 define)
2003 define)
2003 define)
2004 * set:
2004 * set:
2005 <filteredset
2005 <filteredset
2006 <baseset+ [0, 1, 2]>,
2006 <baseset+ [0, 1, 2]>,
2007 <contains 'glob:*'>>
2007 <contains 'glob:*'>>
2008 0
2008 0
2009 1
2009 1
2010 2
2010 2
2011
2011
2012 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2012 and in this example, 'A & B' is rewritten as 'B & A', but 'A' overrides
2013 the order appropriately:
2013 the order appropriately:
2014
2014
2015 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2015 $ try --optimize 'reverse(contains("glob:*")) & (0 + 2 + 1)'
2016 (and
2016 (and
2017 (func
2017 (func
2018 ('symbol', 'reverse')
2018 ('symbol', 'reverse')
2019 (func
2019 (func
2020 ('symbol', 'contains')
2020 ('symbol', 'contains')
2021 ('string', 'glob:*')))
2021 ('string', 'glob:*')))
2022 (group
2022 (group
2023 (or
2023 (or
2024 (list
2024 (list
2025 ('symbol', '0')
2025 ('symbol', '0')
2026 ('symbol', '2')
2026 ('symbol', '2')
2027 ('symbol', '1')))))
2027 ('symbol', '1')))))
2028 * optimized:
2028 * optimized:
2029 (and
2029 (and
2030 (func
2030 (func
2031 ('symbol', '_list')
2031 ('symbol', '_list')
2032 ('string', '0\x002\x001')
2032 ('string', '0\x002\x001')
2033 follow)
2033 follow)
2034 (func
2034 (func
2035 ('symbol', 'reverse')
2035 ('symbol', 'reverse')
2036 (func
2036 (func
2037 ('symbol', 'contains')
2037 ('symbol', 'contains')
2038 ('string', 'glob:*')
2038 ('string', 'glob:*')
2039 define)
2039 define)
2040 define)
2040 define)
2041 define)
2041 define)
2042 * set:
2042 * set:
2043 <filteredset
2043 <filteredset
2044 <baseset- [0, 1, 2]>,
2044 <baseset- [0, 1, 2]>,
2045 <contains 'glob:*'>>
2045 <contains 'glob:*'>>
2046 2
2046 2
2047 1
2047 1
2048 0
2048 0
2049
2049
2050 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
2050 'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
2051 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
2051 matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
2052
2052
2053 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
2053 $ try -p optimized '0:2 & (reverse(contains("a")) + 2)'
2054 * optimized:
2054 * optimized:
2055 (and
2055 (and
2056 (range
2056 (range
2057 ('symbol', '0')
2057 ('symbol', '0')
2058 ('symbol', '2')
2058 ('symbol', '2')
2059 define)
2059 define)
2060 (or
2060 (or
2061 (list
2061 (list
2062 ('symbol', '2')
2062 ('symbol', '2')
2063 (func
2063 (func
2064 ('symbol', 'reverse')
2064 ('symbol', 'reverse')
2065 (func
2065 (func
2066 ('symbol', 'contains')
2066 ('symbol', 'contains')
2067 ('string', 'a')
2067 ('string', 'a')
2068 define)
2068 define)
2069 follow))
2069 follow))
2070 follow)
2070 follow)
2071 define)
2071 define)
2072 * set:
2072 * set:
2073 <filteredset
2073 <filteredset
2074 <spanset+ 0:2>,
2074 <spanset+ 0:2>,
2075 <addset
2075 <addset
2076 <baseset [2]>,
2076 <baseset [2]>,
2077 <filteredset
2077 <filteredset
2078 <fullreposet+ 0:9>,
2078 <fullreposet+ 0:9>,
2079 <contains 'a'>>>>
2079 <contains 'a'>>>>
2080 0
2080 0
2081 1
2081 1
2082 2
2082 2
2083
2083
2084 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
2084 $ try -p optimized '(reverse(contains("a")) + 2) & 0:2'
2085 * optimized:
2085 * optimized:
2086 (and
2086 (and
2087 (range
2087 (range
2088 ('symbol', '0')
2088 ('symbol', '0')
2089 ('symbol', '2')
2089 ('symbol', '2')
2090 follow)
2090 follow)
2091 (or
2091 (or
2092 (list
2092 (list
2093 (func
2093 (func
2094 ('symbol', 'reverse')
2094 ('symbol', 'reverse')
2095 (func
2095 (func
2096 ('symbol', 'contains')
2096 ('symbol', 'contains')
2097 ('string', 'a')
2097 ('string', 'a')
2098 define)
2098 define)
2099 define)
2099 define)
2100 ('symbol', '2'))
2100 ('symbol', '2'))
2101 define)
2101 define)
2102 define)
2102 define)
2103 * set:
2103 * set:
2104 <addset
2104 <addset
2105 <filteredset
2105 <filteredset
2106 <spanset- 0:2>,
2106 <spanset- 0:2>,
2107 <contains 'a'>>,
2107 <contains 'a'>>,
2108 <baseset [2]>>
2108 <baseset [2]>>
2109 1
2109 1
2110 0
2110 0
2111 2
2111 2
2112
2112
2113 test sort revset
2113 test sort revset
2114 --------------------------------------------
2114 --------------------------------------------
2115
2115
2116 test when adding two unordered revsets
2116 test when adding two unordered revsets
2117
2117
2118 $ log 'sort(keyword(issue) or modifies(b))'
2118 $ log 'sort(keyword(issue) or modifies(b))'
2119 4
2119 4
2120 6
2120 6
2121
2121
2122 test when sorting a reversed collection in the same way it is
2122 test when sorting a reversed collection in the same way it is
2123
2123
2124 $ log 'sort(reverse(all()), -rev)'
2124 $ log 'sort(reverse(all()), -rev)'
2125 9
2125 9
2126 8
2126 8
2127 7
2127 7
2128 6
2128 6
2129 5
2129 5
2130 4
2130 4
2131 3
2131 3
2132 2
2132 2
2133 1
2133 1
2134 0
2134 0
2135
2135
2136 test when sorting a reversed collection
2136 test when sorting a reversed collection
2137
2137
2138 $ log 'sort(reverse(all()), rev)'
2138 $ log 'sort(reverse(all()), rev)'
2139 0
2139 0
2140 1
2140 1
2141 2
2141 2
2142 3
2142 3
2143 4
2143 4
2144 5
2144 5
2145 6
2145 6
2146 7
2146 7
2147 8
2147 8
2148 9
2148 9
2149
2149
2150
2150
2151 test sorting two sorted collections in different orders
2151 test sorting two sorted collections in different orders
2152
2152
2153 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2153 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
2154 2
2154 2
2155 6
2155 6
2156 8
2156 8
2157 9
2157 9
2158
2158
2159 test sorting two sorted collections in different orders backwards
2159 test sorting two sorted collections in different orders backwards
2160
2160
2161 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2161 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
2162 9
2162 9
2163 8
2163 8
2164 6
2164 6
2165 2
2165 2
2166
2166
2167 test empty sort key which is noop
2167 test empty sort key which is noop
2168
2168
2169 $ log 'sort(0 + 2 + 1, "")'
2169 $ log 'sort(0 + 2 + 1, "")'
2170 0
2170 0
2171 2
2171 2
2172 1
2172 1
2173
2173
2174 test invalid sort keys
2174 test invalid sort keys
2175
2175
2176 $ log 'sort(all(), -invalid)'
2176 $ log 'sort(all(), -invalid)'
2177 hg: parse error: unknown sort key '-invalid'
2177 hg: parse error: unknown sort key '-invalid'
2178 [255]
2178 [255]
2179
2179
2180 $ cd ..
2180 $ cd ..
2181
2181
2182 test sorting by multiple keys including variable-length strings
2182 test sorting by multiple keys including variable-length strings
2183
2183
2184 $ hg init sorting
2184 $ hg init sorting
2185 $ cd sorting
2185 $ cd sorting
2186 $ cat <<EOF >> .hg/hgrc
2186 $ cat <<EOF >> .hg/hgrc
2187 > [ui]
2187 > [ui]
2188 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2188 > logtemplate = '{rev} {branch|p5}{desc|p5}{author|p5}{date|hgdate}\n'
2189 > [templatealias]
2189 > [templatealias]
2190 > p5(s) = pad(s, 5)
2190 > p5(s) = pad(s, 5)
2191 > EOF
2191 > EOF
2192 $ hg branch -qf b12
2192 $ hg branch -qf b12
2193 $ hg ci -m m111 -u u112 -d '111 10800'
2193 $ hg ci -m m111 -u u112 -d '111 10800'
2194 $ hg branch -qf b11
2194 $ hg branch -qf b11
2195 $ hg ci -m m12 -u u111 -d '112 7200'
2195 $ hg ci -m m12 -u u111 -d '112 7200'
2196 $ hg branch -qf b111
2196 $ hg branch -qf b111
2197 $ hg ci -m m11 -u u12 -d '111 3600'
2197 $ hg ci -m m11 -u u12 -d '111 3600'
2198 $ hg branch -qf b112
2198 $ hg branch -qf b112
2199 $ hg ci -m m111 -u u11 -d '120 0'
2199 $ hg ci -m m111 -u u11 -d '120 0'
2200 $ hg branch -qf b111
2200 $ hg branch -qf b111
2201 $ hg ci -m m112 -u u111 -d '110 14400'
2201 $ hg ci -m m112 -u u111 -d '110 14400'
2202 created new head
2202 created new head
2203
2203
2204 compare revisions (has fast path):
2204 compare revisions (has fast path):
2205
2205
2206 $ hg log -r 'sort(all(), rev)'
2206 $ hg log -r 'sort(all(), rev)'
2207 0 b12 m111 u112 111 10800
2207 0 b12 m111 u112 111 10800
2208 1 b11 m12 u111 112 7200
2208 1 b11 m12 u111 112 7200
2209 2 b111 m11 u12 111 3600
2209 2 b111 m11 u12 111 3600
2210 3 b112 m111 u11 120 0
2210 3 b112 m111 u11 120 0
2211 4 b111 m112 u111 110 14400
2211 4 b111 m112 u111 110 14400
2212
2212
2213 $ hg log -r 'sort(all(), -rev)'
2213 $ hg log -r 'sort(all(), -rev)'
2214 4 b111 m112 u111 110 14400
2214 4 b111 m112 u111 110 14400
2215 3 b112 m111 u11 120 0
2215 3 b112 m111 u11 120 0
2216 2 b111 m11 u12 111 3600
2216 2 b111 m11 u12 111 3600
2217 1 b11 m12 u111 112 7200
2217 1 b11 m12 u111 112 7200
2218 0 b12 m111 u112 111 10800
2218 0 b12 m111 u112 111 10800
2219
2219
2220 compare variable-length strings (issue5218):
2220 compare variable-length strings (issue5218):
2221
2221
2222 $ hg log -r 'sort(all(), branch)'
2222 $ hg log -r 'sort(all(), branch)'
2223 1 b11 m12 u111 112 7200
2223 1 b11 m12 u111 112 7200
2224 2 b111 m11 u12 111 3600
2224 2 b111 m11 u12 111 3600
2225 4 b111 m112 u111 110 14400
2225 4 b111 m112 u111 110 14400
2226 3 b112 m111 u11 120 0
2226 3 b112 m111 u11 120 0
2227 0 b12 m111 u112 111 10800
2227 0 b12 m111 u112 111 10800
2228
2228
2229 $ hg log -r 'sort(all(), -branch)'
2229 $ hg log -r 'sort(all(), -branch)'
2230 0 b12 m111 u112 111 10800
2230 0 b12 m111 u112 111 10800
2231 3 b112 m111 u11 120 0
2231 3 b112 m111 u11 120 0
2232 2 b111 m11 u12 111 3600
2232 2 b111 m11 u12 111 3600
2233 4 b111 m112 u111 110 14400
2233 4 b111 m112 u111 110 14400
2234 1 b11 m12 u111 112 7200
2234 1 b11 m12 u111 112 7200
2235
2235
2236 $ hg log -r 'sort(all(), desc)'
2236 $ hg log -r 'sort(all(), desc)'
2237 2 b111 m11 u12 111 3600
2237 2 b111 m11 u12 111 3600
2238 0 b12 m111 u112 111 10800
2238 0 b12 m111 u112 111 10800
2239 3 b112 m111 u11 120 0
2239 3 b112 m111 u11 120 0
2240 4 b111 m112 u111 110 14400
2240 4 b111 m112 u111 110 14400
2241 1 b11 m12 u111 112 7200
2241 1 b11 m12 u111 112 7200
2242
2242
2243 $ hg log -r 'sort(all(), -desc)'
2243 $ hg log -r 'sort(all(), -desc)'
2244 1 b11 m12 u111 112 7200
2244 1 b11 m12 u111 112 7200
2245 4 b111 m112 u111 110 14400
2245 4 b111 m112 u111 110 14400
2246 0 b12 m111 u112 111 10800
2246 0 b12 m111 u112 111 10800
2247 3 b112 m111 u11 120 0
2247 3 b112 m111 u11 120 0
2248 2 b111 m11 u12 111 3600
2248 2 b111 m11 u12 111 3600
2249
2249
2250 $ hg log -r 'sort(all(), user)'
2250 $ hg log -r 'sort(all(), user)'
2251 3 b112 m111 u11 120 0
2251 3 b112 m111 u11 120 0
2252 1 b11 m12 u111 112 7200
2252 1 b11 m12 u111 112 7200
2253 4 b111 m112 u111 110 14400
2253 4 b111 m112 u111 110 14400
2254 0 b12 m111 u112 111 10800
2254 0 b12 m111 u112 111 10800
2255 2 b111 m11 u12 111 3600
2255 2 b111 m11 u12 111 3600
2256
2256
2257 $ hg log -r 'sort(all(), -user)'
2257 $ hg log -r 'sort(all(), -user)'
2258 2 b111 m11 u12 111 3600
2258 2 b111 m11 u12 111 3600
2259 0 b12 m111 u112 111 10800
2259 0 b12 m111 u112 111 10800
2260 1 b11 m12 u111 112 7200
2260 1 b11 m12 u111 112 7200
2261 4 b111 m112 u111 110 14400
2261 4 b111 m112 u111 110 14400
2262 3 b112 m111 u11 120 0
2262 3 b112 m111 u11 120 0
2263
2263
2264 compare dates (tz offset should have no effect):
2264 compare dates (tz offset should have no effect):
2265
2265
2266 $ hg log -r 'sort(all(), date)'
2266 $ hg log -r 'sort(all(), date)'
2267 4 b111 m112 u111 110 14400
2267 4 b111 m112 u111 110 14400
2268 0 b12 m111 u112 111 10800
2268 0 b12 m111 u112 111 10800
2269 2 b111 m11 u12 111 3600
2269 2 b111 m11 u12 111 3600
2270 1 b11 m12 u111 112 7200
2270 1 b11 m12 u111 112 7200
2271 3 b112 m111 u11 120 0
2271 3 b112 m111 u11 120 0
2272
2272
2273 $ hg log -r 'sort(all(), -date)'
2273 $ hg log -r 'sort(all(), -date)'
2274 3 b112 m111 u11 120 0
2274 3 b112 m111 u11 120 0
2275 1 b11 m12 u111 112 7200
2275 1 b11 m12 u111 112 7200
2276 0 b12 m111 u112 111 10800
2276 0 b12 m111 u112 111 10800
2277 2 b111 m11 u12 111 3600
2277 2 b111 m11 u12 111 3600
2278 4 b111 m112 u111 110 14400
2278 4 b111 m112 u111 110 14400
2279
2279
2280 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2280 be aware that 'sort(x, -k)' is not exactly the same as 'reverse(sort(x, k))'
2281 because '-k' reverses the comparison, not the list itself:
2281 because '-k' reverses the comparison, not the list itself:
2282
2282
2283 $ hg log -r 'sort(0 + 2, date)'
2283 $ hg log -r 'sort(0 + 2, date)'
2284 0 b12 m111 u112 111 10800
2284 0 b12 m111 u112 111 10800
2285 2 b111 m11 u12 111 3600
2285 2 b111 m11 u12 111 3600
2286
2286
2287 $ hg log -r 'sort(0 + 2, -date)'
2287 $ hg log -r 'sort(0 + 2, -date)'
2288 0 b12 m111 u112 111 10800
2288 0 b12 m111 u112 111 10800
2289 2 b111 m11 u12 111 3600
2289 2 b111 m11 u12 111 3600
2290
2290
2291 $ hg log -r 'reverse(sort(0 + 2, date))'
2291 $ hg log -r 'reverse(sort(0 + 2, date))'
2292 2 b111 m11 u12 111 3600
2292 2 b111 m11 u12 111 3600
2293 0 b12 m111 u112 111 10800
2293 0 b12 m111 u112 111 10800
2294
2294
2295 sort by multiple keys:
2295 sort by multiple keys:
2296
2296
2297 $ hg log -r 'sort(all(), "branch -rev")'
2297 $ hg log -r 'sort(all(), "branch -rev")'
2298 1 b11 m12 u111 112 7200
2298 1 b11 m12 u111 112 7200
2299 4 b111 m112 u111 110 14400
2299 4 b111 m112 u111 110 14400
2300 2 b111 m11 u12 111 3600
2300 2 b111 m11 u12 111 3600
2301 3 b112 m111 u11 120 0
2301 3 b112 m111 u11 120 0
2302 0 b12 m111 u112 111 10800
2302 0 b12 m111 u112 111 10800
2303
2303
2304 $ hg log -r 'sort(all(), "-desc -date")'
2304 $ hg log -r 'sort(all(), "-desc -date")'
2305 1 b11 m12 u111 112 7200
2305 1 b11 m12 u111 112 7200
2306 4 b111 m112 u111 110 14400
2306 4 b111 m112 u111 110 14400
2307 3 b112 m111 u11 120 0
2307 3 b112 m111 u11 120 0
2308 0 b12 m111 u112 111 10800
2308 0 b12 m111 u112 111 10800
2309 2 b111 m11 u12 111 3600
2309 2 b111 m11 u12 111 3600
2310
2310
2311 $ hg log -r 'sort(all(), "user -branch date rev")'
2311 $ hg log -r 'sort(all(), "user -branch date rev")'
2312 3 b112 m111 u11 120 0
2312 3 b112 m111 u11 120 0
2313 4 b111 m112 u111 110 14400
2313 4 b111 m112 u111 110 14400
2314 1 b11 m12 u111 112 7200
2314 1 b11 m12 u111 112 7200
2315 0 b12 m111 u112 111 10800
2315 0 b12 m111 u112 111 10800
2316 2 b111 m11 u12 111 3600
2316 2 b111 m11 u12 111 3600
2317
2317
2318 toposort prioritises graph branches
2318 toposort prioritises graph branches
2319
2319
2320 $ hg up 2
2320 $ hg up 2
2321 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2321 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
2322 $ touch a
2322 $ touch a
2323 $ hg addremove
2323 $ hg addremove
2324 adding a
2324 adding a
2325 $ hg ci -m 't1' -u 'tu' -d '130 0'
2325 $ hg ci -m 't1' -u 'tu' -d '130 0'
2326 created new head
2326 created new head
2327 $ echo 'a' >> a
2327 $ echo 'a' >> a
2328 $ hg ci -m 't2' -u 'tu' -d '130 0'
2328 $ hg ci -m 't2' -u 'tu' -d '130 0'
2329 $ hg book book1
2329 $ hg book book1
2330 $ hg up 4
2330 $ hg up 4
2331 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2331 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
2332 (leaving bookmark book1)
2332 (leaving bookmark book1)
2333 $ touch a
2333 $ touch a
2334 $ hg addremove
2334 $ hg addremove
2335 adding a
2335 adding a
2336 $ hg ci -m 't3' -u 'tu' -d '130 0'
2336 $ hg ci -m 't3' -u 'tu' -d '130 0'
2337
2337
2338 $ hg log -r 'sort(all(), topo)'
2338 $ hg log -r 'sort(all(), topo)'
2339 7 b111 t3 tu 130 0
2339 7 b111 t3 tu 130 0
2340 4 b111 m112 u111 110 14400
2340 4 b111 m112 u111 110 14400
2341 3 b112 m111 u11 120 0
2341 3 b112 m111 u11 120 0
2342 6 b111 t2 tu 130 0
2342 6 b111 t2 tu 130 0
2343 5 b111 t1 tu 130 0
2343 5 b111 t1 tu 130 0
2344 2 b111 m11 u12 111 3600
2344 2 b111 m11 u12 111 3600
2345 1 b11 m12 u111 112 7200
2345 1 b11 m12 u111 112 7200
2346 0 b12 m111 u112 111 10800
2346 0 b12 m111 u112 111 10800
2347
2347
2348 $ hg log -r 'sort(all(), -topo)'
2348 $ hg log -r 'sort(all(), -topo)'
2349 0 b12 m111 u112 111 10800
2349 0 b12 m111 u112 111 10800
2350 1 b11 m12 u111 112 7200
2350 1 b11 m12 u111 112 7200
2351 2 b111 m11 u12 111 3600
2351 2 b111 m11 u12 111 3600
2352 5 b111 t1 tu 130 0
2352 5 b111 t1 tu 130 0
2353 6 b111 t2 tu 130 0
2353 6 b111 t2 tu 130 0
2354 3 b112 m111 u11 120 0
2354 3 b112 m111 u11 120 0
2355 4 b111 m112 u111 110 14400
2355 4 b111 m112 u111 110 14400
2356 7 b111 t3 tu 130 0
2356 7 b111 t3 tu 130 0
2357
2357
2358 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2358 $ hg log -r 'sort(all(), topo, topo.firstbranch=book1)'
2359 6 b111 t2 tu 130 0
2359 6 b111 t2 tu 130 0
2360 5 b111 t1 tu 130 0
2360 5 b111 t1 tu 130 0
2361 7 b111 t3 tu 130 0
2361 7 b111 t3 tu 130 0
2362 4 b111 m112 u111 110 14400
2362 4 b111 m112 u111 110 14400
2363 3 b112 m111 u11 120 0
2363 3 b112 m111 u11 120 0
2364 2 b111 m11 u12 111 3600
2364 2 b111 m11 u12 111 3600
2365 1 b11 m12 u111 112 7200
2365 1 b11 m12 u111 112 7200
2366 0 b12 m111 u112 111 10800
2366 0 b12 m111 u112 111 10800
2367
2367
2368 topographical sorting can't be combined with other sort keys, and you can't
2368 topographical sorting can't be combined with other sort keys, and you can't
2369 use the topo.firstbranch option when topo sort is not active:
2369 use the topo.firstbranch option when topo sort is not active:
2370
2370
2371 $ hg log -r 'sort(all(), "topo user")'
2371 $ hg log -r 'sort(all(), "topo user")'
2372 hg: parse error: topo sort order cannot be combined with other sort keys
2372 hg: parse error: topo sort order cannot be combined with other sort keys
2373 [255]
2373 [255]
2374
2374
2375 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2375 $ hg log -r 'sort(all(), user, topo.firstbranch=book1)'
2376 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2376 hg: parse error: topo.firstbranch can only be used when using the topo sort key
2377 [255]
2377 [255]
2378
2378
2379 topo.firstbranch should accept any kind of expressions:
2379 topo.firstbranch should accept any kind of expressions:
2380
2380
2381 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2381 $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
2382 0 b12 m111 u112 111 10800
2382 0 b12 m111 u112 111 10800
2383
2383
2384 $ cd ..
2384 $ cd ..
2385 $ cd repo
2385 $ cd repo
2386
2386
2387 test subtracting something from an addset
2387 test subtracting something from an addset
2388
2388
2389 $ log '(outgoing() or removes(a)) - removes(a)'
2389 $ log '(outgoing() or removes(a)) - removes(a)'
2390 8
2390 8
2391 9
2391 9
2392
2392
2393 test intersecting something with an addset
2393 test intersecting something with an addset
2394
2394
2395 $ log 'parents(outgoing() or removes(a))'
2395 $ log 'parents(outgoing() or removes(a))'
2396 1
2396 1
2397 4
2397 4
2398 5
2398 5
2399 8
2399 8
2400
2400
2401 test that `or` operation combines elements in the right order:
2401 test that `or` operation combines elements in the right order:
2402
2402
2403 $ log '3:4 or 2:5'
2403 $ log '3:4 or 2:5'
2404 3
2404 3
2405 4
2405 4
2406 2
2406 2
2407 5
2407 5
2408 $ log '3:4 or 5:2'
2408 $ log '3:4 or 5:2'
2409 3
2409 3
2410 4
2410 4
2411 5
2411 5
2412 2
2412 2
2413 $ log 'sort(3:4 or 2:5)'
2413 $ log 'sort(3:4 or 2:5)'
2414 2
2414 2
2415 3
2415 3
2416 4
2416 4
2417 5
2417 5
2418 $ log 'sort(3:4 or 5:2)'
2418 $ log 'sort(3:4 or 5:2)'
2419 2
2419 2
2420 3
2420 3
2421 4
2421 4
2422 5
2422 5
2423
2423
2424 test that more than one `-r`s are combined in the right order and deduplicated:
2424 test that more than one `-r`s are combined in the right order and deduplicated:
2425
2425
2426 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2426 $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
2427 3
2427 3
2428 4
2428 4
2429 5
2429 5
2430 2
2430 2
2431 0
2431 0
2432 1
2432 1
2433
2433
2434 test that `or` operation skips duplicated revisions from right-hand side
2434 test that `or` operation skips duplicated revisions from right-hand side
2435
2435
2436 $ try 'reverse(1::5) or ancestors(4)'
2436 $ try 'reverse(1::5) or ancestors(4)'
2437 (or
2437 (or
2438 (list
2438 (list
2439 (func
2439 (func
2440 ('symbol', 'reverse')
2440 ('symbol', 'reverse')
2441 (dagrange
2441 (dagrange
2442 ('symbol', '1')
2442 ('symbol', '1')
2443 ('symbol', '5')))
2443 ('symbol', '5')))
2444 (func
2444 (func
2445 ('symbol', 'ancestors')
2445 ('symbol', 'ancestors')
2446 ('symbol', '4'))))
2446 ('symbol', '4'))))
2447 * set:
2447 * set:
2448 <addset
2448 <addset
2449 <baseset- [1, 3, 5]>,
2449 <baseset- [1, 3, 5]>,
2450 <generatorset+>>
2450 <generatorset+>>
2451 5
2451 5
2452 3
2452 3
2453 1
2453 1
2454 0
2454 0
2455 2
2455 2
2456 4
2456 4
2457 $ try 'sort(ancestors(4) or reverse(1::5))'
2457 $ try 'sort(ancestors(4) or reverse(1::5))'
2458 (func
2458 (func
2459 ('symbol', 'sort')
2459 ('symbol', 'sort')
2460 (or
2460 (or
2461 (list
2461 (list
2462 (func
2462 (func
2463 ('symbol', 'ancestors')
2463 ('symbol', 'ancestors')
2464 ('symbol', '4'))
2464 ('symbol', '4'))
2465 (func
2465 (func
2466 ('symbol', 'reverse')
2466 ('symbol', 'reverse')
2467 (dagrange
2467 (dagrange
2468 ('symbol', '1')
2468 ('symbol', '1')
2469 ('symbol', '5'))))))
2469 ('symbol', '5'))))))
2470 * set:
2470 * set:
2471 <addset+
2471 <addset+
2472 <generatorset+>,
2472 <generatorset+>,
2473 <baseset- [1, 3, 5]>>
2473 <baseset- [1, 3, 5]>>
2474 0
2474 0
2475 1
2475 1
2476 2
2476 2
2477 3
2477 3
2478 4
2478 4
2479 5
2479 5
2480
2480
2481 test optimization of trivial `or` operation
2481 test optimization of trivial `or` operation
2482
2482
2483 $ try --optimize '0|(1)|"2"|-2|tip|null'
2483 $ try --optimize '0|(1)|"2"|-2|tip|null'
2484 (or
2484 (or
2485 (list
2485 (list
2486 ('symbol', '0')
2486 ('symbol', '0')
2487 (group
2487 (group
2488 ('symbol', '1'))
2488 ('symbol', '1'))
2489 ('string', '2')
2489 ('string', '2')
2490 (negate
2490 (negate
2491 ('symbol', '2'))
2491 ('symbol', '2'))
2492 ('symbol', 'tip')
2492 ('symbol', 'tip')
2493 ('symbol', 'null')))
2493 ('symbol', 'null')))
2494 * optimized:
2494 * optimized:
2495 (func
2495 (func
2496 ('symbol', '_list')
2496 ('symbol', '_list')
2497 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2497 ('string', '0\x001\x002\x00-2\x00tip\x00null')
2498 define)
2498 define)
2499 * set:
2499 * set:
2500 <baseset [0, 1, 2, 8, 9, -1]>
2500 <baseset [0, 1, 2, 8, 9, -1]>
2501 0
2501 0
2502 1
2502 1
2503 2
2503 2
2504 8
2504 8
2505 9
2505 9
2506 -1
2506 -1
2507
2507
2508 $ try --optimize '0|1|2:3'
2508 $ try --optimize '0|1|2:3'
2509 (or
2509 (or
2510 (list
2510 (list
2511 ('symbol', '0')
2511 ('symbol', '0')
2512 ('symbol', '1')
2512 ('symbol', '1')
2513 (range
2513 (range
2514 ('symbol', '2')
2514 ('symbol', '2')
2515 ('symbol', '3'))))
2515 ('symbol', '3'))))
2516 * optimized:
2516 * optimized:
2517 (or
2517 (or
2518 (list
2518 (list
2519 (func
2519 (func
2520 ('symbol', '_list')
2520 ('symbol', '_list')
2521 ('string', '0\x001')
2521 ('string', '0\x001')
2522 define)
2522 define)
2523 (range
2523 (range
2524 ('symbol', '2')
2524 ('symbol', '2')
2525 ('symbol', '3')
2525 ('symbol', '3')
2526 define))
2526 define))
2527 define)
2527 define)
2528 * set:
2528 * set:
2529 <addset
2529 <addset
2530 <baseset [0, 1]>,
2530 <baseset [0, 1]>,
2531 <spanset+ 2:3>>
2531 <spanset+ 2:3>>
2532 0
2532 0
2533 1
2533 1
2534 2
2534 2
2535 3
2535 3
2536
2536
2537 $ try --optimize '0:1|2|3:4|5|6'
2537 $ try --optimize '0:1|2|3:4|5|6'
2538 (or
2538 (or
2539 (list
2539 (list
2540 (range
2540 (range
2541 ('symbol', '0')
2541 ('symbol', '0')
2542 ('symbol', '1'))
2542 ('symbol', '1'))
2543 ('symbol', '2')
2543 ('symbol', '2')
2544 (range
2544 (range
2545 ('symbol', '3')
2545 ('symbol', '3')
2546 ('symbol', '4'))
2546 ('symbol', '4'))
2547 ('symbol', '5')
2547 ('symbol', '5')
2548 ('symbol', '6')))
2548 ('symbol', '6')))
2549 * optimized:
2549 * optimized:
2550 (or
2550 (or
2551 (list
2551 (list
2552 (range
2552 (range
2553 ('symbol', '0')
2553 ('symbol', '0')
2554 ('symbol', '1')
2554 ('symbol', '1')
2555 define)
2555 define)
2556 ('symbol', '2')
2556 ('symbol', '2')
2557 (range
2557 (range
2558 ('symbol', '3')
2558 ('symbol', '3')
2559 ('symbol', '4')
2559 ('symbol', '4')
2560 define)
2560 define)
2561 (func
2561 (func
2562 ('symbol', '_list')
2562 ('symbol', '_list')
2563 ('string', '5\x006')
2563 ('string', '5\x006')
2564 define))
2564 define))
2565 define)
2565 define)
2566 * set:
2566 * set:
2567 <addset
2567 <addset
2568 <addset
2568 <addset
2569 <spanset+ 0:1>,
2569 <spanset+ 0:1>,
2570 <baseset [2]>>,
2570 <baseset [2]>>,
2571 <addset
2571 <addset
2572 <spanset+ 3:4>,
2572 <spanset+ 3:4>,
2573 <baseset [5, 6]>>>
2573 <baseset [5, 6]>>>
2574 0
2574 0
2575 1
2575 1
2576 2
2576 2
2577 3
2577 3
2578 4
2578 4
2579 5
2579 5
2580 6
2580 6
2581
2581
2582 unoptimized `or` looks like this
2582 unoptimized `or` looks like this
2583
2583
2584 $ try --no-optimized -p analyzed '0|1|2|3|4'
2584 $ try --no-optimized -p analyzed '0|1|2|3|4'
2585 * analyzed:
2585 * analyzed:
2586 (or
2586 (or
2587 (list
2587 (list
2588 ('symbol', '0')
2588 ('symbol', '0')
2589 ('symbol', '1')
2589 ('symbol', '1')
2590 ('symbol', '2')
2590 ('symbol', '2')
2591 ('symbol', '3')
2591 ('symbol', '3')
2592 ('symbol', '4'))
2592 ('symbol', '4'))
2593 define)
2593 define)
2594 * set:
2594 * set:
2595 <addset
2595 <addset
2596 <addset
2596 <addset
2597 <baseset [0]>,
2597 <baseset [0]>,
2598 <baseset [1]>>,
2598 <baseset [1]>>,
2599 <addset
2599 <addset
2600 <baseset [2]>,
2600 <baseset [2]>,
2601 <addset
2601 <addset
2602 <baseset [3]>,
2602 <baseset [3]>,
2603 <baseset [4]>>>>
2603 <baseset [4]>>>>
2604 0
2604 0
2605 1
2605 1
2606 2
2606 2
2607 3
2607 3
2608 4
2608 4
2609
2609
2610 test that `_list` should be narrowed by provided `subset`
2610 test that `_list` should be narrowed by provided `subset`
2611
2611
2612 $ log '0:2 and (null|1|2|3)'
2612 $ log '0:2 and (null|1|2|3)'
2613 1
2613 1
2614 2
2614 2
2615
2615
2616 test that `_list` should remove duplicates
2616 test that `_list` should remove duplicates
2617
2617
2618 $ log '0|1|2|1|2|-1|tip'
2618 $ log '0|1|2|1|2|-1|tip'
2619 0
2619 0
2620 1
2620 1
2621 2
2621 2
2622 9
2622 9
2623
2623
2624 test unknown revision in `_list`
2624 test unknown revision in `_list`
2625
2625
2626 $ log '0|unknown'
2626 $ log '0|unknown'
2627 abort: unknown revision 'unknown'!
2627 abort: unknown revision 'unknown'!
2628 [255]
2628 [255]
2629
2629
2630 test integer range in `_list`
2630 test integer range in `_list`
2631
2631
2632 $ log '-1|-10'
2632 $ log '-1|-10'
2633 9
2633 9
2634 0
2634 0
2635
2635
2636 $ log '-10|-11'
2636 $ log '-10|-11'
2637 abort: unknown revision '-11'!
2637 abort: unknown revision '-11'!
2638 [255]
2638 [255]
2639
2639
2640 $ log '9|10'
2640 $ log '9|10'
2641 abort: unknown revision '10'!
2641 abort: unknown revision '10'!
2642 [255]
2642 [255]
2643
2643
2644 test '0000' != '0' in `_list`
2644 test '0000' != '0' in `_list`
2645
2645
2646 $ log '0|0000'
2646 $ log '0|0000'
2647 0
2647 0
2648 -1
2648 -1
2649
2649
2650 test ',' in `_list`
2650 test ',' in `_list`
2651 $ log '0,1'
2651 $ log '0,1'
2652 hg: parse error: can't use a list in this context
2652 hg: parse error: can't use a list in this context
2653 (see hg help "revsets.x or y")
2653 (see hg help "revsets.x or y")
2654 [255]
2654 [255]
2655 $ try '0,1,2'
2655 $ try '0,1,2'
2656 (list
2656 (list
2657 ('symbol', '0')
2657 ('symbol', '0')
2658 ('symbol', '1')
2658 ('symbol', '1')
2659 ('symbol', '2'))
2659 ('symbol', '2'))
2660 hg: parse error: can't use a list in this context
2660 hg: parse error: can't use a list in this context
2661 (see hg help "revsets.x or y")
2661 (see hg help "revsets.x or y")
2662 [255]
2662 [255]
2663
2663
2664 test that chained `or` operations make balanced addsets
2664 test that chained `or` operations make balanced addsets
2665
2665
2666 $ try '0:1|1:2|2:3|3:4|4:5'
2666 $ try '0:1|1:2|2:3|3:4|4:5'
2667 (or
2667 (or
2668 (list
2668 (list
2669 (range
2669 (range
2670 ('symbol', '0')
2670 ('symbol', '0')
2671 ('symbol', '1'))
2671 ('symbol', '1'))
2672 (range
2672 (range
2673 ('symbol', '1')
2673 ('symbol', '1')
2674 ('symbol', '2'))
2674 ('symbol', '2'))
2675 (range
2675 (range
2676 ('symbol', '2')
2676 ('symbol', '2')
2677 ('symbol', '3'))
2677 ('symbol', '3'))
2678 (range
2678 (range
2679 ('symbol', '3')
2679 ('symbol', '3')
2680 ('symbol', '4'))
2680 ('symbol', '4'))
2681 (range
2681 (range
2682 ('symbol', '4')
2682 ('symbol', '4')
2683 ('symbol', '5'))))
2683 ('symbol', '5'))))
2684 * set:
2684 * set:
2685 <addset
2685 <addset
2686 <addset
2686 <addset
2687 <spanset+ 0:1>,
2687 <spanset+ 0:1>,
2688 <spanset+ 1:2>>,
2688 <spanset+ 1:2>>,
2689 <addset
2689 <addset
2690 <spanset+ 2:3>,
2690 <spanset+ 2:3>,
2691 <addset
2691 <addset
2692 <spanset+ 3:4>,
2692 <spanset+ 3:4>,
2693 <spanset+ 4:5>>>>
2693 <spanset+ 4:5>>>>
2694 0
2694 0
2695 1
2695 1
2696 2
2696 2
2697 3
2697 3
2698 4
2698 4
2699 5
2699 5
2700
2700
2701 no crash by empty group "()" while optimizing `or` operations
2701 no crash by empty group "()" while optimizing `or` operations
2702
2702
2703 $ try --optimize '0|()'
2703 $ try --optimize '0|()'
2704 (or
2704 (or
2705 (list
2705 (list
2706 ('symbol', '0')
2706 ('symbol', '0')
2707 (group
2707 (group
2708 None)))
2708 None)))
2709 * optimized:
2709 * optimized:
2710 (or
2710 (or
2711 (list
2711 (list
2712 ('symbol', '0')
2712 ('symbol', '0')
2713 None)
2713 None)
2714 define)
2714 define)
2715 hg: parse error: missing argument
2715 hg: parse error: missing argument
2716 [255]
2716 [255]
2717
2717
2718 test that chained `or` operations never eat up stack (issue4624)
2718 test that chained `or` operations never eat up stack (issue4624)
2719 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2719 (uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
2720
2720
2721 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2721 $ hg log -T '{rev}\n' -r `python -c "print '+'.join(['0:1'] * 500)"`
2722 0
2722 0
2723 1
2723 1
2724
2724
2725 test that repeated `-r` options never eat up stack (issue4565)
2725 test that repeated `-r` options never eat up stack (issue4565)
2726 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2726 (uses `-r 0::1` to avoid possible optimization at old-style parser)
2727
2727
2728 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2728 $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
2729 0
2729 0
2730 1
2730 1
2731
2731
2732 check that conversion to only works
2732 check that conversion to only works
2733 $ try --optimize '::3 - ::1'
2733 $ try --optimize '::3 - ::1'
2734 (minus
2734 (minus
2735 (dagrangepre
2735 (dagrangepre
2736 ('symbol', '3'))
2736 ('symbol', '3'))
2737 (dagrangepre
2737 (dagrangepre
2738 ('symbol', '1')))
2738 ('symbol', '1')))
2739 * optimized:
2739 * optimized:
2740 (func
2740 (func
2741 ('symbol', 'only')
2741 ('symbol', 'only')
2742 (list
2742 (list
2743 ('symbol', '3')
2743 ('symbol', '3')
2744 ('symbol', '1'))
2744 ('symbol', '1'))
2745 define)
2745 define)
2746 * set:
2746 * set:
2747 <baseset+ [3]>
2747 <baseset+ [3]>
2748 3
2748 3
2749 $ try --optimize 'ancestors(1) - ancestors(3)'
2749 $ try --optimize 'ancestors(1) - ancestors(3)'
2750 (minus
2750 (minus
2751 (func
2751 (func
2752 ('symbol', 'ancestors')
2752 ('symbol', 'ancestors')
2753 ('symbol', '1'))
2753 ('symbol', '1'))
2754 (func
2754 (func
2755 ('symbol', 'ancestors')
2755 ('symbol', 'ancestors')
2756 ('symbol', '3')))
2756 ('symbol', '3')))
2757 * optimized:
2757 * optimized:
2758 (func
2758 (func
2759 ('symbol', 'only')
2759 ('symbol', 'only')
2760 (list
2760 (list
2761 ('symbol', '1')
2761 ('symbol', '1')
2762 ('symbol', '3'))
2762 ('symbol', '3'))
2763 define)
2763 define)
2764 * set:
2764 * set:
2765 <baseset+ []>
2765 <baseset+ []>
2766 $ try --optimize 'not ::2 and ::6'
2766 $ try --optimize 'not ::2 and ::6'
2767 (and
2767 (and
2768 (not
2768 (not
2769 (dagrangepre
2769 (dagrangepre
2770 ('symbol', '2')))
2770 ('symbol', '2')))
2771 (dagrangepre
2771 (dagrangepre
2772 ('symbol', '6')))
2772 ('symbol', '6')))
2773 * optimized:
2773 * optimized:
2774 (func
2774 (func
2775 ('symbol', 'only')
2775 ('symbol', 'only')
2776 (list
2776 (list
2777 ('symbol', '6')
2777 ('symbol', '6')
2778 ('symbol', '2'))
2778 ('symbol', '2'))
2779 define)
2779 define)
2780 * set:
2780 * set:
2781 <baseset+ [3, 4, 5, 6]>
2781 <baseset+ [3, 4, 5, 6]>
2782 3
2782 3
2783 4
2783 4
2784 5
2784 5
2785 6
2785 6
2786 $ try --optimize 'ancestors(6) and not ancestors(4)'
2786 $ try --optimize 'ancestors(6) and not ancestors(4)'
2787 (and
2787 (and
2788 (func
2788 (func
2789 ('symbol', 'ancestors')
2789 ('symbol', 'ancestors')
2790 ('symbol', '6'))
2790 ('symbol', '6'))
2791 (not
2791 (not
2792 (func
2792 (func
2793 ('symbol', 'ancestors')
2793 ('symbol', 'ancestors')
2794 ('symbol', '4'))))
2794 ('symbol', '4'))))
2795 * optimized:
2795 * optimized:
2796 (func
2796 (func
2797 ('symbol', 'only')
2797 ('symbol', 'only')
2798 (list
2798 (list
2799 ('symbol', '6')
2799 ('symbol', '6')
2800 ('symbol', '4'))
2800 ('symbol', '4'))
2801 define)
2801 define)
2802 * set:
2802 * set:
2803 <baseset+ [3, 5, 6]>
2803 <baseset+ [3, 5, 6]>
2804 3
2804 3
2805 5
2805 5
2806 6
2806 6
2807
2807
2808 no crash by empty group "()" while optimizing to "only()"
2808 no crash by empty group "()" while optimizing to "only()"
2809
2809
2810 $ try --optimize '::1 and ()'
2810 $ try --optimize '::1 and ()'
2811 (and
2811 (and
2812 (dagrangepre
2812 (dagrangepre
2813 ('symbol', '1'))
2813 ('symbol', '1'))
2814 (group
2814 (group
2815 None))
2815 None))
2816 * optimized:
2816 * optimized:
2817 (and
2817 (and
2818 None
2818 None
2819 (func
2819 (func
2820 ('symbol', 'ancestors')
2820 ('symbol', 'ancestors')
2821 ('symbol', '1')
2821 ('symbol', '1')
2822 define)
2822 define)
2823 define)
2823 define)
2824 hg: parse error: missing argument
2824 hg: parse error: missing argument
2825 [255]
2825 [255]
2826
2826
2827 invalid function call should not be optimized to only()
2827 invalid function call should not be optimized to only()
2828
2828
2829 $ log '"ancestors"(6) and not ancestors(4)'
2829 $ log '"ancestors"(6) and not ancestors(4)'
2830 hg: parse error: not a symbol
2830 hg: parse error: not a symbol
2831 [255]
2831 [255]
2832
2832
2833 $ log 'ancestors(6) and not "ancestors"(4)'
2833 $ log 'ancestors(6) and not "ancestors"(4)'
2834 hg: parse error: not a symbol
2834 hg: parse error: not a symbol
2835 [255]
2835 [255]
2836
2836
2837 we can use patterns when searching for tags
2837 we can use patterns when searching for tags
2838
2838
2839 $ log 'tag("1..*")'
2839 $ log 'tag("1..*")'
2840 abort: tag '1..*' does not exist!
2840 abort: tag '1..*' does not exist!
2841 [255]
2841 [255]
2842 $ log 'tag("re:1..*")'
2842 $ log 'tag("re:1..*")'
2843 6
2843 6
2844 $ log 'tag("re:[0-9].[0-9]")'
2844 $ log 'tag("re:[0-9].[0-9]")'
2845 6
2845 6
2846 $ log 'tag("literal:1.0")'
2846 $ log 'tag("literal:1.0")'
2847 6
2847 6
2848 $ log 'tag("re:0..*")'
2848 $ log 'tag("re:0..*")'
2849
2849
2850 $ log 'tag(unknown)'
2850 $ log 'tag(unknown)'
2851 abort: tag 'unknown' does not exist!
2851 abort: tag 'unknown' does not exist!
2852 [255]
2852 [255]
2853 $ log 'tag("re:unknown")'
2853 $ log 'tag("re:unknown")'
2854 $ log 'present(tag("unknown"))'
2854 $ log 'present(tag("unknown"))'
2855 $ log 'present(tag("re:unknown"))'
2855 $ log 'present(tag("re:unknown"))'
2856 $ log 'branch(unknown)'
2856 $ log 'branch(unknown)'
2857 abort: unknown revision 'unknown'!
2857 abort: unknown revision 'unknown'!
2858 [255]
2858 [255]
2859 $ log 'branch("literal:unknown")'
2859 $ log 'branch("literal:unknown")'
2860 abort: branch 'unknown' does not exist!
2860 abort: branch 'unknown' does not exist!
2861 [255]
2861 [255]
2862 $ log 'branch("re:unknown")'
2862 $ log 'branch("re:unknown")'
2863 $ log 'present(branch("unknown"))'
2863 $ log 'present(branch("unknown"))'
2864 $ log 'present(branch("re:unknown"))'
2864 $ log 'present(branch("re:unknown"))'
2865 $ log 'user(bob)'
2865 $ log 'user(bob)'
2866 2
2866 2
2867
2867
2868 $ log '4::8'
2868 $ log '4::8'
2869 4
2869 4
2870 8
2870 8
2871 $ log '4:8'
2871 $ log '4:8'
2872 4
2872 4
2873 5
2873 5
2874 6
2874 6
2875 7
2875 7
2876 8
2876 8
2877
2877
2878 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2878 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
2879 4
2879 4
2880 2
2880 2
2881 5
2881 5
2882
2882
2883 $ log 'not 0 and 0:2'
2883 $ log 'not 0 and 0:2'
2884 1
2884 1
2885 2
2885 2
2886 $ log 'not 1 and 0:2'
2886 $ log 'not 1 and 0:2'
2887 0
2887 0
2888 2
2888 2
2889 $ log 'not 2 and 0:2'
2889 $ log 'not 2 and 0:2'
2890 0
2890 0
2891 1
2891 1
2892 $ log '(1 and 2)::'
2892 $ log '(1 and 2)::'
2893 $ log '(1 and 2):'
2893 $ log '(1 and 2):'
2894 $ log '(1 and 2):3'
2894 $ log '(1 and 2):3'
2895 $ log 'sort(head(), -rev)'
2895 $ log 'sort(head(), -rev)'
2896 9
2896 9
2897 7
2897 7
2898 6
2898 6
2899 5
2899 5
2900 4
2900 4
2901 3
2901 3
2902 2
2902 2
2903 1
2903 1
2904 0
2904 0
2905 $ log '4::8 - 8'
2905 $ log '4::8 - 8'
2906 4
2906 4
2907
2907
2908 matching() should preserve the order of the input set:
2908 matching() should preserve the order of the input set:
2909
2909
2910 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2910 $ log '(2 or 3 or 1) and matching(1 or 2 or 3)'
2911 2
2911 2
2912 3
2912 3
2913 1
2913 1
2914
2914
2915 $ log 'named("unknown")'
2915 $ log 'named("unknown")'
2916 abort: namespace 'unknown' does not exist!
2916 abort: namespace 'unknown' does not exist!
2917 [255]
2917 [255]
2918 $ log 'named("re:unknown")'
2918 $ log 'named("re:unknown")'
2919 abort: no namespace exists that match 'unknown'!
2919 abort: no namespace exists that match 'unknown'!
2920 [255]
2920 [255]
2921 $ log 'present(named("unknown"))'
2921 $ log 'present(named("unknown"))'
2922 $ log 'present(named("re:unknown"))'
2922 $ log 'present(named("re:unknown"))'
2923
2923
2924 $ log 'tag()'
2924 $ log 'tag()'
2925 6
2925 6
2926 $ log 'named("tags")'
2926 $ log 'named("tags")'
2927 6
2927 6
2928
2928
2929 issue2437
2929 issue2437
2930
2930
2931 $ log '3 and p1(5)'
2931 $ log '3 and p1(5)'
2932 3
2932 3
2933 $ log '4 and p2(6)'
2933 $ log '4 and p2(6)'
2934 4
2934 4
2935 $ log '1 and parents(:2)'
2935 $ log '1 and parents(:2)'
2936 1
2936 1
2937 $ log '2 and children(1:)'
2937 $ log '2 and children(1:)'
2938 2
2938 2
2939 $ log 'roots(all()) or roots(all())'
2939 $ log 'roots(all()) or roots(all())'
2940 0
2940 0
2941 $ hg debugrevspec 'roots(all()) or roots(all())'
2941 $ hg debugrevspec 'roots(all()) or roots(all())'
2942 0
2942 0
2943 $ log 'heads(branch(é)) or heads(branch(é))'
2943 $ log 'heads(branch(é)) or heads(branch(é))'
2944 9
2944 9
2945 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
2945 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
2946 4
2946 4
2947
2947
2948 issue2654: report a parse error if the revset was not completely parsed
2948 issue2654: report a parse error if the revset was not completely parsed
2949
2949
2950 $ log '1 OR 2'
2950 $ log '1 OR 2'
2951 hg: parse error at 2: invalid token
2951 hg: parse error at 2: invalid token
2952 [255]
2952 [255]
2953
2953
2954 or operator should preserve ordering:
2954 or operator should preserve ordering:
2955 $ log 'reverse(2::4) or tip'
2955 $ log 'reverse(2::4) or tip'
2956 4
2956 4
2957 2
2957 2
2958 9
2958 9
2959
2959
2960 parentrevspec
2960 parentrevspec
2961
2961
2962 $ log 'merge()^0'
2962 $ log 'merge()^0'
2963 6
2963 6
2964 $ log 'merge()^'
2964 $ log 'merge()^'
2965 5
2965 5
2966 $ log 'merge()^1'
2966 $ log 'merge()^1'
2967 5
2967 5
2968 $ log 'merge()^2'
2968 $ log 'merge()^2'
2969 4
2969 4
2970 $ log '(not merge())^2'
2970 $ log '(not merge())^2'
2971 $ log 'merge()^^'
2971 $ log 'merge()^^'
2972 3
2972 3
2973 $ log 'merge()^1^'
2973 $ log 'merge()^1^'
2974 3
2974 3
2975 $ log 'merge()^^^'
2975 $ log 'merge()^^^'
2976 1
2976 1
2977
2977
2978 $ log '(merge() | 0)~-1'
2979 7
2980 1
2981 $ log 'merge()~-1'
2982 7
2983 $ log 'tip~-1'
2984 $ log '(tip | merge())~-1'
2985 7
2978 $ log 'merge()~0'
2986 $ log 'merge()~0'
2979 6
2987 6
2980 $ log 'merge()~1'
2988 $ log 'merge()~1'
2981 5
2989 5
2982 $ log 'merge()~2'
2990 $ log 'merge()~2'
2983 3
2991 3
2984 $ log 'merge()~2^1'
2992 $ log 'merge()~2^1'
2985 1
2993 1
2986 $ log 'merge()~3'
2994 $ log 'merge()~3'
2987 1
2995 1
2988
2996
2989 $ log '(-3:tip)^'
2997 $ log '(-3:tip)^'
2990 4
2998 4
2991 6
2999 6
2992 8
3000 8
2993
3001
2994 $ log 'tip^foo'
3002 $ log 'tip^foo'
2995 hg: parse error: ^ expects a number 0, 1, or 2
3003 hg: parse error: ^ expects a number 0, 1, or 2
2996 [255]
3004 [255]
2997
3005
3006 $ log 'branchpoint()~-1'
3007 abort: revision in set has more than one child!
3008 [255]
3009
2998 Bogus function gets suggestions
3010 Bogus function gets suggestions
2999 $ log 'add()'
3011 $ log 'add()'
3000 hg: parse error: unknown identifier: add
3012 hg: parse error: unknown identifier: add
3001 (did you mean adds?)
3013 (did you mean adds?)
3002 [255]
3014 [255]
3003 $ log 'added()'
3015 $ log 'added()'
3004 hg: parse error: unknown identifier: added
3016 hg: parse error: unknown identifier: added
3005 (did you mean adds?)
3017 (did you mean adds?)
3006 [255]
3018 [255]
3007 $ log 'remo()'
3019 $ log 'remo()'
3008 hg: parse error: unknown identifier: remo
3020 hg: parse error: unknown identifier: remo
3009 (did you mean one of remote, removes?)
3021 (did you mean one of remote, removes?)
3010 [255]
3022 [255]
3011 $ log 'babar()'
3023 $ log 'babar()'
3012 hg: parse error: unknown identifier: babar
3024 hg: parse error: unknown identifier: babar
3013 [255]
3025 [255]
3014
3026
3015 Bogus function with a similar internal name doesn't suggest the internal name
3027 Bogus function with a similar internal name doesn't suggest the internal name
3016 $ log 'matches()'
3028 $ log 'matches()'
3017 hg: parse error: unknown identifier: matches
3029 hg: parse error: unknown identifier: matches
3018 (did you mean matching?)
3030 (did you mean matching?)
3019 [255]
3031 [255]
3020
3032
3021 Undocumented functions aren't suggested as similar either
3033 Undocumented functions aren't suggested as similar either
3022 $ log 'tagged2()'
3034 $ log 'tagged2()'
3023 hg: parse error: unknown identifier: tagged2
3035 hg: parse error: unknown identifier: tagged2
3024 [255]
3036 [255]
3025
3037
3026 multiple revspecs
3038 multiple revspecs
3027
3039
3028 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3040 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
3029 8
3041 8
3030 9
3042 9
3031 4
3043 4
3032 5
3044 5
3033 6
3045 6
3034 7
3046 7
3035
3047
3036 test usage in revpair (with "+")
3048 test usage in revpair (with "+")
3037
3049
3038 (real pair)
3050 (real pair)
3039
3051
3040 $ hg diff -r 'tip^^' -r 'tip'
3052 $ hg diff -r 'tip^^' -r 'tip'
3041 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3053 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3042 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3054 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3043 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3055 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3044 @@ -0,0 +1,1 @@
3056 @@ -0,0 +1,1 @@
3045 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3057 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3046 $ hg diff -r 'tip^^::tip'
3058 $ hg diff -r 'tip^^::tip'
3047 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3059 diff -r 2326846efdab -r 24286f4ae135 .hgtags
3048 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3060 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3049 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3061 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
3050 @@ -0,0 +1,1 @@
3062 @@ -0,0 +1,1 @@
3051 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3063 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3052
3064
3053 (single rev)
3065 (single rev)
3054
3066
3055 $ hg diff -r 'tip^' -r 'tip^'
3067 $ hg diff -r 'tip^' -r 'tip^'
3056 $ hg diff -r 'tip^:tip^'
3068 $ hg diff -r 'tip^:tip^'
3057
3069
3058 (single rev that does not looks like a range)
3070 (single rev that does not looks like a range)
3059
3071
3060 $ hg diff -r 'tip^::tip^ or tip^'
3072 $ hg diff -r 'tip^::tip^ or tip^'
3061 diff -r d5d0dcbdc4d9 .hgtags
3073 diff -r d5d0dcbdc4d9 .hgtags
3062 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3074 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3063 +++ b/.hgtags * (glob)
3075 +++ b/.hgtags * (glob)
3064 @@ -0,0 +1,1 @@
3076 @@ -0,0 +1,1 @@
3065 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3077 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3066 $ hg diff -r 'tip^ or tip^'
3078 $ hg diff -r 'tip^ or tip^'
3067 diff -r d5d0dcbdc4d9 .hgtags
3079 diff -r d5d0dcbdc4d9 .hgtags
3068 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3080 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3069 +++ b/.hgtags * (glob)
3081 +++ b/.hgtags * (glob)
3070 @@ -0,0 +1,1 @@
3082 @@ -0,0 +1,1 @@
3071 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3083 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
3072
3084
3073 (no rev)
3085 (no rev)
3074
3086
3075 $ hg diff -r 'author("babar") or author("celeste")'
3087 $ hg diff -r 'author("babar") or author("celeste")'
3076 abort: empty revision range
3088 abort: empty revision range
3077 [255]
3089 [255]
3078
3090
3079 aliases:
3091 aliases:
3080
3092
3081 $ echo '[revsetalias]' >> .hg/hgrc
3093 $ echo '[revsetalias]' >> .hg/hgrc
3082 $ echo 'm = merge()' >> .hg/hgrc
3094 $ echo 'm = merge()' >> .hg/hgrc
3083 (revset aliases can override builtin revsets)
3095 (revset aliases can override builtin revsets)
3084 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3096 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
3085 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3097 $ echo 'sincem = descendants(m)' >> .hg/hgrc
3086 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3098 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
3087 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3099 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3088 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3100 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
3089
3101
3090 $ try m
3102 $ try m
3091 ('symbol', 'm')
3103 ('symbol', 'm')
3092 * expanded:
3104 * expanded:
3093 (func
3105 (func
3094 ('symbol', 'merge')
3106 ('symbol', 'merge')
3095 None)
3107 None)
3096 * set:
3108 * set:
3097 <filteredset
3109 <filteredset
3098 <fullreposet+ 0:9>,
3110 <fullreposet+ 0:9>,
3099 <merge>>
3111 <merge>>
3100 6
3112 6
3101
3113
3102 $ HGPLAIN=1
3114 $ HGPLAIN=1
3103 $ export HGPLAIN
3115 $ export HGPLAIN
3104 $ try m
3116 $ try m
3105 ('symbol', 'm')
3117 ('symbol', 'm')
3106 abort: unknown revision 'm'!
3118 abort: unknown revision 'm'!
3107 [255]
3119 [255]
3108
3120
3109 $ HGPLAINEXCEPT=revsetalias
3121 $ HGPLAINEXCEPT=revsetalias
3110 $ export HGPLAINEXCEPT
3122 $ export HGPLAINEXCEPT
3111 $ try m
3123 $ try m
3112 ('symbol', 'm')
3124 ('symbol', 'm')
3113 * expanded:
3125 * expanded:
3114 (func
3126 (func
3115 ('symbol', 'merge')
3127 ('symbol', 'merge')
3116 None)
3128 None)
3117 * set:
3129 * set:
3118 <filteredset
3130 <filteredset
3119 <fullreposet+ 0:9>,
3131 <fullreposet+ 0:9>,
3120 <merge>>
3132 <merge>>
3121 6
3133 6
3122
3134
3123 $ unset HGPLAIN
3135 $ unset HGPLAIN
3124 $ unset HGPLAINEXCEPT
3136 $ unset HGPLAINEXCEPT
3125
3137
3126 $ try 'p2(.)'
3138 $ try 'p2(.)'
3127 (func
3139 (func
3128 ('symbol', 'p2')
3140 ('symbol', 'p2')
3129 ('symbol', '.'))
3141 ('symbol', '.'))
3130 * expanded:
3142 * expanded:
3131 (func
3143 (func
3132 ('symbol', 'p1')
3144 ('symbol', 'p1')
3133 ('symbol', '.'))
3145 ('symbol', '.'))
3134 * set:
3146 * set:
3135 <baseset+ [8]>
3147 <baseset+ [8]>
3136 8
3148 8
3137
3149
3138 $ HGPLAIN=1
3150 $ HGPLAIN=1
3139 $ export HGPLAIN
3151 $ export HGPLAIN
3140 $ try 'p2(.)'
3152 $ try 'p2(.)'
3141 (func
3153 (func
3142 ('symbol', 'p2')
3154 ('symbol', 'p2')
3143 ('symbol', '.'))
3155 ('symbol', '.'))
3144 * set:
3156 * set:
3145 <baseset+ []>
3157 <baseset+ []>
3146
3158
3147 $ HGPLAINEXCEPT=revsetalias
3159 $ HGPLAINEXCEPT=revsetalias
3148 $ export HGPLAINEXCEPT
3160 $ export HGPLAINEXCEPT
3149 $ try 'p2(.)'
3161 $ try 'p2(.)'
3150 (func
3162 (func
3151 ('symbol', 'p2')
3163 ('symbol', 'p2')
3152 ('symbol', '.'))
3164 ('symbol', '.'))
3153 * expanded:
3165 * expanded:
3154 (func
3166 (func
3155 ('symbol', 'p1')
3167 ('symbol', 'p1')
3156 ('symbol', '.'))
3168 ('symbol', '.'))
3157 * set:
3169 * set:
3158 <baseset+ [8]>
3170 <baseset+ [8]>
3159 8
3171 8
3160
3172
3161 $ unset HGPLAIN
3173 $ unset HGPLAIN
3162 $ unset HGPLAINEXCEPT
3174 $ unset HGPLAINEXCEPT
3163
3175
3164 test alias recursion
3176 test alias recursion
3165
3177
3166 $ try sincem
3178 $ try sincem
3167 ('symbol', 'sincem')
3179 ('symbol', 'sincem')
3168 * expanded:
3180 * expanded:
3169 (func
3181 (func
3170 ('symbol', 'descendants')
3182 ('symbol', 'descendants')
3171 (func
3183 (func
3172 ('symbol', 'merge')
3184 ('symbol', 'merge')
3173 None))
3185 None))
3174 * set:
3186 * set:
3175 <addset+
3187 <addset+
3176 <filteredset
3188 <filteredset
3177 <fullreposet+ 0:9>,
3189 <fullreposet+ 0:9>,
3178 <merge>>,
3190 <merge>>,
3179 <generatorset+>>
3191 <generatorset+>>
3180 6
3192 6
3181 7
3193 7
3182
3194
3183 test infinite recursion
3195 test infinite recursion
3184
3196
3185 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3197 $ echo 'recurse1 = recurse2' >> .hg/hgrc
3186 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3198 $ echo 'recurse2 = recurse1' >> .hg/hgrc
3187 $ try recurse1
3199 $ try recurse1
3188 ('symbol', 'recurse1')
3200 ('symbol', 'recurse1')
3189 hg: parse error: infinite expansion of revset alias "recurse1" detected
3201 hg: parse error: infinite expansion of revset alias "recurse1" detected
3190 [255]
3202 [255]
3191
3203
3192 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3204 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
3193 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3205 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
3194 $ try "level2(level1(1, 2), 3)"
3206 $ try "level2(level1(1, 2), 3)"
3195 (func
3207 (func
3196 ('symbol', 'level2')
3208 ('symbol', 'level2')
3197 (list
3209 (list
3198 (func
3210 (func
3199 ('symbol', 'level1')
3211 ('symbol', 'level1')
3200 (list
3212 (list
3201 ('symbol', '1')
3213 ('symbol', '1')
3202 ('symbol', '2')))
3214 ('symbol', '2')))
3203 ('symbol', '3')))
3215 ('symbol', '3')))
3204 * expanded:
3216 * expanded:
3205 (or
3217 (or
3206 (list
3218 (list
3207 ('symbol', '3')
3219 ('symbol', '3')
3208 (or
3220 (or
3209 (list
3221 (list
3210 ('symbol', '1')
3222 ('symbol', '1')
3211 ('symbol', '2')))))
3223 ('symbol', '2')))))
3212 * set:
3224 * set:
3213 <addset
3225 <addset
3214 <baseset [3]>,
3226 <baseset [3]>,
3215 <baseset [1, 2]>>
3227 <baseset [1, 2]>>
3216 3
3228 3
3217 1
3229 1
3218 2
3230 2
3219
3231
3220 test nesting and variable passing
3232 test nesting and variable passing
3221
3233
3222 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3234 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
3223 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3235 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
3224 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3236 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
3225 $ try 'nested(2:5)'
3237 $ try 'nested(2:5)'
3226 (func
3238 (func
3227 ('symbol', 'nested')
3239 ('symbol', 'nested')
3228 (range
3240 (range
3229 ('symbol', '2')
3241 ('symbol', '2')
3230 ('symbol', '5')))
3242 ('symbol', '5')))
3231 * expanded:
3243 * expanded:
3232 (func
3244 (func
3233 ('symbol', 'max')
3245 ('symbol', 'max')
3234 (range
3246 (range
3235 ('symbol', '2')
3247 ('symbol', '2')
3236 ('symbol', '5')))
3248 ('symbol', '5')))
3237 * set:
3249 * set:
3238 <baseset
3250 <baseset
3239 <max
3251 <max
3240 <fullreposet+ 0:9>,
3252 <fullreposet+ 0:9>,
3241 <spanset+ 2:5>>>
3253 <spanset+ 2:5>>>
3242 5
3254 5
3243
3255
3244 test chained `or` operations are flattened at parsing phase
3256 test chained `or` operations are flattened at parsing phase
3245
3257
3246 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3258 $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
3247 $ try 'chainedorops(0:1, 1:2, 2:3)'
3259 $ try 'chainedorops(0:1, 1:2, 2:3)'
3248 (func
3260 (func
3249 ('symbol', 'chainedorops')
3261 ('symbol', 'chainedorops')
3250 (list
3262 (list
3251 (range
3263 (range
3252 ('symbol', '0')
3264 ('symbol', '0')
3253 ('symbol', '1'))
3265 ('symbol', '1'))
3254 (range
3266 (range
3255 ('symbol', '1')
3267 ('symbol', '1')
3256 ('symbol', '2'))
3268 ('symbol', '2'))
3257 (range
3269 (range
3258 ('symbol', '2')
3270 ('symbol', '2')
3259 ('symbol', '3'))))
3271 ('symbol', '3'))))
3260 * expanded:
3272 * expanded:
3261 (or
3273 (or
3262 (list
3274 (list
3263 (range
3275 (range
3264 ('symbol', '0')
3276 ('symbol', '0')
3265 ('symbol', '1'))
3277 ('symbol', '1'))
3266 (range
3278 (range
3267 ('symbol', '1')
3279 ('symbol', '1')
3268 ('symbol', '2'))
3280 ('symbol', '2'))
3269 (range
3281 (range
3270 ('symbol', '2')
3282 ('symbol', '2')
3271 ('symbol', '3'))))
3283 ('symbol', '3'))))
3272 * set:
3284 * set:
3273 <addset
3285 <addset
3274 <spanset+ 0:1>,
3286 <spanset+ 0:1>,
3275 <addset
3287 <addset
3276 <spanset+ 1:2>,
3288 <spanset+ 1:2>,
3277 <spanset+ 2:3>>>
3289 <spanset+ 2:3>>>
3278 0
3290 0
3279 1
3291 1
3280 2
3292 2
3281 3
3293 3
3282
3294
3283 test variable isolation, variable placeholders are rewritten as string
3295 test variable isolation, variable placeholders are rewritten as string
3284 then parsed and matched again as string. Check they do not leak too
3296 then parsed and matched again as string. Check they do not leak too
3285 far away.
3297 far away.
3286
3298
3287 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3299 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
3288 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3300 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
3289 $ try 'callinjection(2:5)'
3301 $ try 'callinjection(2:5)'
3290 (func
3302 (func
3291 ('symbol', 'callinjection')
3303 ('symbol', 'callinjection')
3292 (range
3304 (range
3293 ('symbol', '2')
3305 ('symbol', '2')
3294 ('symbol', '5')))
3306 ('symbol', '5')))
3295 * expanded:
3307 * expanded:
3296 (func
3308 (func
3297 ('symbol', 'descendants')
3309 ('symbol', 'descendants')
3298 (func
3310 (func
3299 ('symbol', 'max')
3311 ('symbol', 'max')
3300 ('string', '$1')))
3312 ('string', '$1')))
3301 abort: unknown revision '$1'!
3313 abort: unknown revision '$1'!
3302 [255]
3314 [255]
3303
3315
3304 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3316 test scope of alias expansion: 'universe' is expanded prior to 'shadowall(0)',
3305 but 'all()' should never be substituted to '0()'.
3317 but 'all()' should never be substituted to '0()'.
3306
3318
3307 $ echo 'universe = all()' >> .hg/hgrc
3319 $ echo 'universe = all()' >> .hg/hgrc
3308 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3320 $ echo 'shadowall(all) = all and universe' >> .hg/hgrc
3309 $ try 'shadowall(0)'
3321 $ try 'shadowall(0)'
3310 (func
3322 (func
3311 ('symbol', 'shadowall')
3323 ('symbol', 'shadowall')
3312 ('symbol', '0'))
3324 ('symbol', '0'))
3313 * expanded:
3325 * expanded:
3314 (and
3326 (and
3315 ('symbol', '0')
3327 ('symbol', '0')
3316 (func
3328 (func
3317 ('symbol', 'all')
3329 ('symbol', 'all')
3318 None))
3330 None))
3319 * set:
3331 * set:
3320 <filteredset
3332 <filteredset
3321 <baseset [0]>,
3333 <baseset [0]>,
3322 <spanset+ 0:9>>
3334 <spanset+ 0:9>>
3323 0
3335 0
3324
3336
3325 test unknown reference:
3337 test unknown reference:
3326
3338
3327 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3339 $ try "unknownref(0)" --config 'revsetalias.unknownref($1)=$1:$2'
3328 (func
3340 (func
3329 ('symbol', 'unknownref')
3341 ('symbol', 'unknownref')
3330 ('symbol', '0'))
3342 ('symbol', '0'))
3331 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3343 abort: bad definition of revset alias "unknownref": invalid symbol '$2'
3332 [255]
3344 [255]
3333
3345
3334 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3346 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
3335 ('symbol', 'tip')
3347 ('symbol', 'tip')
3336 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3348 warning: bad definition of revset alias "anotherbadone": at 7: not a prefix: end
3337 * set:
3349 * set:
3338 <baseset [9]>
3350 <baseset [9]>
3339 9
3351 9
3340
3352
3341 $ try 'tip'
3353 $ try 'tip'
3342 ('symbol', 'tip')
3354 ('symbol', 'tip')
3343 * set:
3355 * set:
3344 <baseset [9]>
3356 <baseset [9]>
3345 9
3357 9
3346
3358
3347 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3359 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
3348 ('symbol', 'tip')
3360 ('symbol', 'tip')
3349 warning: bad declaration of revset alias "bad name": at 4: invalid token
3361 warning: bad declaration of revset alias "bad name": at 4: invalid token
3350 * set:
3362 * set:
3351 <baseset [9]>
3363 <baseset [9]>
3352 9
3364 9
3353 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3365 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
3354 $ try 'strictreplacing("foo", tip)'
3366 $ try 'strictreplacing("foo", tip)'
3355 (func
3367 (func
3356 ('symbol', 'strictreplacing')
3368 ('symbol', 'strictreplacing')
3357 (list
3369 (list
3358 ('string', 'foo')
3370 ('string', 'foo')
3359 ('symbol', 'tip')))
3371 ('symbol', 'tip')))
3360 * expanded:
3372 * expanded:
3361 (or
3373 (or
3362 (list
3374 (list
3363 ('symbol', 'tip')
3375 ('symbol', 'tip')
3364 (func
3376 (func
3365 ('symbol', 'desc')
3377 ('symbol', 'desc')
3366 ('string', '$1'))))
3378 ('string', '$1'))))
3367 * set:
3379 * set:
3368 <addset
3380 <addset
3369 <baseset [9]>,
3381 <baseset [9]>,
3370 <filteredset
3382 <filteredset
3371 <fullreposet+ 0:9>,
3383 <fullreposet+ 0:9>,
3372 <desc '$1'>>>
3384 <desc '$1'>>>
3373 9
3385 9
3374
3386
3375 $ try 'd(2:5)'
3387 $ try 'd(2:5)'
3376 (func
3388 (func
3377 ('symbol', 'd')
3389 ('symbol', 'd')
3378 (range
3390 (range
3379 ('symbol', '2')
3391 ('symbol', '2')
3380 ('symbol', '5')))
3392 ('symbol', '5')))
3381 * expanded:
3393 * expanded:
3382 (func
3394 (func
3383 ('symbol', 'reverse')
3395 ('symbol', 'reverse')
3384 (func
3396 (func
3385 ('symbol', 'sort')
3397 ('symbol', 'sort')
3386 (list
3398 (list
3387 (range
3399 (range
3388 ('symbol', '2')
3400 ('symbol', '2')
3389 ('symbol', '5'))
3401 ('symbol', '5'))
3390 ('symbol', 'date'))))
3402 ('symbol', 'date'))))
3391 * set:
3403 * set:
3392 <baseset [4, 5, 3, 2]>
3404 <baseset [4, 5, 3, 2]>
3393 4
3405 4
3394 5
3406 5
3395 3
3407 3
3396 2
3408 2
3397 $ try 'rs(2 or 3, date)'
3409 $ try 'rs(2 or 3, date)'
3398 (func
3410 (func
3399 ('symbol', 'rs')
3411 ('symbol', 'rs')
3400 (list
3412 (list
3401 (or
3413 (or
3402 (list
3414 (list
3403 ('symbol', '2')
3415 ('symbol', '2')
3404 ('symbol', '3')))
3416 ('symbol', '3')))
3405 ('symbol', 'date')))
3417 ('symbol', 'date')))
3406 * expanded:
3418 * expanded:
3407 (func
3419 (func
3408 ('symbol', 'reverse')
3420 ('symbol', 'reverse')
3409 (func
3421 (func
3410 ('symbol', 'sort')
3422 ('symbol', 'sort')
3411 (list
3423 (list
3412 (or
3424 (or
3413 (list
3425 (list
3414 ('symbol', '2')
3426 ('symbol', '2')
3415 ('symbol', '3')))
3427 ('symbol', '3')))
3416 ('symbol', 'date'))))
3428 ('symbol', 'date'))))
3417 * set:
3429 * set:
3418 <baseset [3, 2]>
3430 <baseset [3, 2]>
3419 3
3431 3
3420 2
3432 2
3421 $ try 'rs()'
3433 $ try 'rs()'
3422 (func
3434 (func
3423 ('symbol', 'rs')
3435 ('symbol', 'rs')
3424 None)
3436 None)
3425 hg: parse error: invalid number of arguments: 0
3437 hg: parse error: invalid number of arguments: 0
3426 [255]
3438 [255]
3427 $ try 'rs(2)'
3439 $ try 'rs(2)'
3428 (func
3440 (func
3429 ('symbol', 'rs')
3441 ('symbol', 'rs')
3430 ('symbol', '2'))
3442 ('symbol', '2'))
3431 hg: parse error: invalid number of arguments: 1
3443 hg: parse error: invalid number of arguments: 1
3432 [255]
3444 [255]
3433 $ try 'rs(2, data, 7)'
3445 $ try 'rs(2, data, 7)'
3434 (func
3446 (func
3435 ('symbol', 'rs')
3447 ('symbol', 'rs')
3436 (list
3448 (list
3437 ('symbol', '2')
3449 ('symbol', '2')
3438 ('symbol', 'data')
3450 ('symbol', 'data')
3439 ('symbol', '7')))
3451 ('symbol', '7')))
3440 hg: parse error: invalid number of arguments: 3
3452 hg: parse error: invalid number of arguments: 3
3441 [255]
3453 [255]
3442 $ try 'rs4(2 or 3, x, x, date)'
3454 $ try 'rs4(2 or 3, x, x, date)'
3443 (func
3455 (func
3444 ('symbol', 'rs4')
3456 ('symbol', 'rs4')
3445 (list
3457 (list
3446 (or
3458 (or
3447 (list
3459 (list
3448 ('symbol', '2')
3460 ('symbol', '2')
3449 ('symbol', '3')))
3461 ('symbol', '3')))
3450 ('symbol', 'x')
3462 ('symbol', 'x')
3451 ('symbol', 'x')
3463 ('symbol', 'x')
3452 ('symbol', 'date')))
3464 ('symbol', 'date')))
3453 * expanded:
3465 * expanded:
3454 (func
3466 (func
3455 ('symbol', 'reverse')
3467 ('symbol', 'reverse')
3456 (func
3468 (func
3457 ('symbol', 'sort')
3469 ('symbol', 'sort')
3458 (list
3470 (list
3459 (or
3471 (or
3460 (list
3472 (list
3461 ('symbol', '2')
3473 ('symbol', '2')
3462 ('symbol', '3')))
3474 ('symbol', '3')))
3463 ('symbol', 'date'))))
3475 ('symbol', 'date'))))
3464 * set:
3476 * set:
3465 <baseset [3, 2]>
3477 <baseset [3, 2]>
3466 3
3478 3
3467 2
3479 2
3468
3480
3469 issue4553: check that revset aliases override existing hash prefix
3481 issue4553: check that revset aliases override existing hash prefix
3470
3482
3471 $ hg log -qr e
3483 $ hg log -qr e
3472 6:e0cc66ef77e8
3484 6:e0cc66ef77e8
3473
3485
3474 $ hg log -qr e --config revsetalias.e="all()"
3486 $ hg log -qr e --config revsetalias.e="all()"
3475 0:2785f51eece5
3487 0:2785f51eece5
3476 1:d75937da8da0
3488 1:d75937da8da0
3477 2:5ed5505e9f1c
3489 2:5ed5505e9f1c
3478 3:8528aa5637f2
3490 3:8528aa5637f2
3479 4:2326846efdab
3491 4:2326846efdab
3480 5:904fa392b941
3492 5:904fa392b941
3481 6:e0cc66ef77e8
3493 6:e0cc66ef77e8
3482 7:013af1973af4
3494 7:013af1973af4
3483 8:d5d0dcbdc4d9
3495 8:d5d0dcbdc4d9
3484 9:24286f4ae135
3496 9:24286f4ae135
3485
3497
3486 $ hg log -qr e: --config revsetalias.e="0"
3498 $ hg log -qr e: --config revsetalias.e="0"
3487 0:2785f51eece5
3499 0:2785f51eece5
3488 1:d75937da8da0
3500 1:d75937da8da0
3489 2:5ed5505e9f1c
3501 2:5ed5505e9f1c
3490 3:8528aa5637f2
3502 3:8528aa5637f2
3491 4:2326846efdab
3503 4:2326846efdab
3492 5:904fa392b941
3504 5:904fa392b941
3493 6:e0cc66ef77e8
3505 6:e0cc66ef77e8
3494 7:013af1973af4
3506 7:013af1973af4
3495 8:d5d0dcbdc4d9
3507 8:d5d0dcbdc4d9
3496 9:24286f4ae135
3508 9:24286f4ae135
3497
3509
3498 $ hg log -qr :e --config revsetalias.e="9"
3510 $ hg log -qr :e --config revsetalias.e="9"
3499 0:2785f51eece5
3511 0:2785f51eece5
3500 1:d75937da8da0
3512 1:d75937da8da0
3501 2:5ed5505e9f1c
3513 2:5ed5505e9f1c
3502 3:8528aa5637f2
3514 3:8528aa5637f2
3503 4:2326846efdab
3515 4:2326846efdab
3504 5:904fa392b941
3516 5:904fa392b941
3505 6:e0cc66ef77e8
3517 6:e0cc66ef77e8
3506 7:013af1973af4
3518 7:013af1973af4
3507 8:d5d0dcbdc4d9
3519 8:d5d0dcbdc4d9
3508 9:24286f4ae135
3520 9:24286f4ae135
3509
3521
3510 $ hg log -qr e:
3522 $ hg log -qr e:
3511 6:e0cc66ef77e8
3523 6:e0cc66ef77e8
3512 7:013af1973af4
3524 7:013af1973af4
3513 8:d5d0dcbdc4d9
3525 8:d5d0dcbdc4d9
3514 9:24286f4ae135
3526 9:24286f4ae135
3515
3527
3516 $ hg log -qr :e
3528 $ hg log -qr :e
3517 0:2785f51eece5
3529 0:2785f51eece5
3518 1:d75937da8da0
3530 1:d75937da8da0
3519 2:5ed5505e9f1c
3531 2:5ed5505e9f1c
3520 3:8528aa5637f2
3532 3:8528aa5637f2
3521 4:2326846efdab
3533 4:2326846efdab
3522 5:904fa392b941
3534 5:904fa392b941
3523 6:e0cc66ef77e8
3535 6:e0cc66ef77e8
3524
3536
3525 issue2549 - correct optimizations
3537 issue2549 - correct optimizations
3526
3538
3527 $ try 'limit(1 or 2 or 3, 2) and not 2'
3539 $ try 'limit(1 or 2 or 3, 2) and not 2'
3528 (and
3540 (and
3529 (func
3541 (func
3530 ('symbol', 'limit')
3542 ('symbol', 'limit')
3531 (list
3543 (list
3532 (or
3544 (or
3533 (list
3545 (list
3534 ('symbol', '1')
3546 ('symbol', '1')
3535 ('symbol', '2')
3547 ('symbol', '2')
3536 ('symbol', '3')))
3548 ('symbol', '3')))
3537 ('symbol', '2')))
3549 ('symbol', '2')))
3538 (not
3550 (not
3539 ('symbol', '2')))
3551 ('symbol', '2')))
3540 * set:
3552 * set:
3541 <filteredset
3553 <filteredset
3542 <baseset
3554 <baseset
3543 <limit n=2, offset=0,
3555 <limit n=2, offset=0,
3544 <fullreposet+ 0:9>,
3556 <fullreposet+ 0:9>,
3545 <baseset [1, 2, 3]>>>,
3557 <baseset [1, 2, 3]>>>,
3546 <not
3558 <not
3547 <baseset [2]>>>
3559 <baseset [2]>>>
3548 1
3560 1
3549 $ try 'max(1 or 2) and not 2'
3561 $ try 'max(1 or 2) and not 2'
3550 (and
3562 (and
3551 (func
3563 (func
3552 ('symbol', 'max')
3564 ('symbol', 'max')
3553 (or
3565 (or
3554 (list
3566 (list
3555 ('symbol', '1')
3567 ('symbol', '1')
3556 ('symbol', '2'))))
3568 ('symbol', '2'))))
3557 (not
3569 (not
3558 ('symbol', '2')))
3570 ('symbol', '2')))
3559 * set:
3571 * set:
3560 <filteredset
3572 <filteredset
3561 <baseset
3573 <baseset
3562 <max
3574 <max
3563 <fullreposet+ 0:9>,
3575 <fullreposet+ 0:9>,
3564 <baseset [1, 2]>>>,
3576 <baseset [1, 2]>>>,
3565 <not
3577 <not
3566 <baseset [2]>>>
3578 <baseset [2]>>>
3567 $ try 'min(1 or 2) and not 1'
3579 $ try 'min(1 or 2) and not 1'
3568 (and
3580 (and
3569 (func
3581 (func
3570 ('symbol', 'min')
3582 ('symbol', 'min')
3571 (or
3583 (or
3572 (list
3584 (list
3573 ('symbol', '1')
3585 ('symbol', '1')
3574 ('symbol', '2'))))
3586 ('symbol', '2'))))
3575 (not
3587 (not
3576 ('symbol', '1')))
3588 ('symbol', '1')))
3577 * set:
3589 * set:
3578 <filteredset
3590 <filteredset
3579 <baseset
3591 <baseset
3580 <min
3592 <min
3581 <fullreposet+ 0:9>,
3593 <fullreposet+ 0:9>,
3582 <baseset [1, 2]>>>,
3594 <baseset [1, 2]>>>,
3583 <not
3595 <not
3584 <baseset [1]>>>
3596 <baseset [1]>>>
3585 $ try 'last(1 or 2, 1) and not 2'
3597 $ try 'last(1 or 2, 1) and not 2'
3586 (and
3598 (and
3587 (func
3599 (func
3588 ('symbol', 'last')
3600 ('symbol', 'last')
3589 (list
3601 (list
3590 (or
3602 (or
3591 (list
3603 (list
3592 ('symbol', '1')
3604 ('symbol', '1')
3593 ('symbol', '2')))
3605 ('symbol', '2')))
3594 ('symbol', '1')))
3606 ('symbol', '1')))
3595 (not
3607 (not
3596 ('symbol', '2')))
3608 ('symbol', '2')))
3597 * set:
3609 * set:
3598 <filteredset
3610 <filteredset
3599 <baseset
3611 <baseset
3600 <last n=1,
3612 <last n=1,
3601 <fullreposet+ 0:9>,
3613 <fullreposet+ 0:9>,
3602 <baseset [2, 1]>>>,
3614 <baseset [2, 1]>>>,
3603 <not
3615 <not
3604 <baseset [2]>>>
3616 <baseset [2]>>>
3605
3617
3606 issue4289 - ordering of built-ins
3618 issue4289 - ordering of built-ins
3607 $ hg log -M -q -r 3:2
3619 $ hg log -M -q -r 3:2
3608 3:8528aa5637f2
3620 3:8528aa5637f2
3609 2:5ed5505e9f1c
3621 2:5ed5505e9f1c
3610
3622
3611 test revsets started with 40-chars hash (issue3669)
3623 test revsets started with 40-chars hash (issue3669)
3612
3624
3613 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3625 $ ISSUE3669_TIP=`hg tip --template '{node}'`
3614 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3626 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
3615 9
3627 9
3616 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3628 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
3617 8
3629 8
3618
3630
3619 test or-ed indirect predicates (issue3775)
3631 test or-ed indirect predicates (issue3775)
3620
3632
3621 $ log '6 or 6^1' | sort
3633 $ log '6 or 6^1' | sort
3622 5
3634 5
3623 6
3635 6
3624 $ log '6^1 or 6' | sort
3636 $ log '6^1 or 6' | sort
3625 5
3637 5
3626 6
3638 6
3627 $ log '4 or 4~1' | sort
3639 $ log '4 or 4~1' | sort
3628 2
3640 2
3629 4
3641 4
3630 $ log '4~1 or 4' | sort
3642 $ log '4~1 or 4' | sort
3631 2
3643 2
3632 4
3644 4
3633 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3645 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
3634 0
3646 0
3635 1
3647 1
3636 2
3648 2
3637 3
3649 3
3638 4
3650 4
3639 5
3651 5
3640 6
3652 6
3641 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3653 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
3642 0
3654 0
3643 1
3655 1
3644 2
3656 2
3645 3
3657 3
3646 4
3658 4
3647 5
3659 5
3648 6
3660 6
3649
3661
3650 tests for 'remote()' predicate:
3662 tests for 'remote()' predicate:
3651 #. (csets in remote) (id) (remote)
3663 #. (csets in remote) (id) (remote)
3652 1. less than local current branch "default"
3664 1. less than local current branch "default"
3653 2. same with local specified "default"
3665 2. same with local specified "default"
3654 3. more than local specified specified
3666 3. more than local specified specified
3655
3667
3656 $ hg clone --quiet -U . ../remote3
3668 $ hg clone --quiet -U . ../remote3
3657 $ cd ../remote3
3669 $ cd ../remote3
3658 $ hg update -q 7
3670 $ hg update -q 7
3659 $ echo r > r
3671 $ echo r > r
3660 $ hg ci -Aqm 10
3672 $ hg ci -Aqm 10
3661 $ log 'remote()'
3673 $ log 'remote()'
3662 7
3674 7
3663 $ log 'remote("a-b-c-")'
3675 $ log 'remote("a-b-c-")'
3664 2
3676 2
3665 $ cd ../repo
3677 $ cd ../repo
3666 $ log 'remote(".a.b.c.", "../remote3")'
3678 $ log 'remote(".a.b.c.", "../remote3")'
3667
3679
3668 tests for concatenation of strings/symbols by "##"
3680 tests for concatenation of strings/symbols by "##"
3669
3681
3670 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3682 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
3671 (_concat
3683 (_concat
3672 (_concat
3684 (_concat
3673 (_concat
3685 (_concat
3674 ('symbol', '278')
3686 ('symbol', '278')
3675 ('string', '5f5'))
3687 ('string', '5f5'))
3676 ('symbol', '1ee'))
3688 ('symbol', '1ee'))
3677 ('string', 'ce5'))
3689 ('string', 'ce5'))
3678 * concatenated:
3690 * concatenated:
3679 ('string', '2785f51eece5')
3691 ('string', '2785f51eece5')
3680 * set:
3692 * set:
3681 <baseset [0]>
3693 <baseset [0]>
3682 0
3694 0
3683
3695
3684 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3696 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
3685 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3697 $ try "cat4(278, '5f5', 1ee, 'ce5')"
3686 (func
3698 (func
3687 ('symbol', 'cat4')
3699 ('symbol', 'cat4')
3688 (list
3700 (list
3689 ('symbol', '278')
3701 ('symbol', '278')
3690 ('string', '5f5')
3702 ('string', '5f5')
3691 ('symbol', '1ee')
3703 ('symbol', '1ee')
3692 ('string', 'ce5')))
3704 ('string', 'ce5')))
3693 * expanded:
3705 * expanded:
3694 (_concat
3706 (_concat
3695 (_concat
3707 (_concat
3696 (_concat
3708 (_concat
3697 ('symbol', '278')
3709 ('symbol', '278')
3698 ('string', '5f5'))
3710 ('string', '5f5'))
3699 ('symbol', '1ee'))
3711 ('symbol', '1ee'))
3700 ('string', 'ce5'))
3712 ('string', 'ce5'))
3701 * concatenated:
3713 * concatenated:
3702 ('string', '2785f51eece5')
3714 ('string', '2785f51eece5')
3703 * set:
3715 * set:
3704 <baseset [0]>
3716 <baseset [0]>
3705 0
3717 0
3706
3718
3707 (check concatenation in alias nesting)
3719 (check concatenation in alias nesting)
3708
3720
3709 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3721 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
3710 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3722 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
3711 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3723 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
3712 0
3724 0
3713
3725
3714 (check operator priority)
3726 (check operator priority)
3715
3727
3716 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3728 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
3717 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3729 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
3718 0
3730 0
3719 4
3731 4
3720
3732
3721 $ cd ..
3733 $ cd ..
3722
3734
3723 prepare repository that has "default" branches of multiple roots
3735 prepare repository that has "default" branches of multiple roots
3724
3736
3725 $ hg init namedbranch
3737 $ hg init namedbranch
3726 $ cd namedbranch
3738 $ cd namedbranch
3727
3739
3728 $ echo default0 >> a
3740 $ echo default0 >> a
3729 $ hg ci -Aqm0
3741 $ hg ci -Aqm0
3730 $ echo default1 >> a
3742 $ echo default1 >> a
3731 $ hg ci -m1
3743 $ hg ci -m1
3732
3744
3733 $ hg branch -q stable
3745 $ hg branch -q stable
3734 $ echo stable2 >> a
3746 $ echo stable2 >> a
3735 $ hg ci -m2
3747 $ hg ci -m2
3736 $ echo stable3 >> a
3748 $ echo stable3 >> a
3737 $ hg ci -m3
3749 $ hg ci -m3
3738
3750
3739 $ hg update -q null
3751 $ hg update -q null
3740 $ echo default4 >> a
3752 $ echo default4 >> a
3741 $ hg ci -Aqm4
3753 $ hg ci -Aqm4
3742 $ echo default5 >> a
3754 $ echo default5 >> a
3743 $ hg ci -m5
3755 $ hg ci -m5
3744
3756
3745 "null" revision belongs to "default" branch (issue4683)
3757 "null" revision belongs to "default" branch (issue4683)
3746
3758
3747 $ log 'branch(null)'
3759 $ log 'branch(null)'
3748 0
3760 0
3749 1
3761 1
3750 4
3762 4
3751 5
3763 5
3752
3764
3753 "null" revision belongs to "default" branch, but it shouldn't appear in set
3765 "null" revision belongs to "default" branch, but it shouldn't appear in set
3754 unless explicitly specified (issue4682)
3766 unless explicitly specified (issue4682)
3755
3767
3756 $ log 'children(branch(default))'
3768 $ log 'children(branch(default))'
3757 1
3769 1
3758 2
3770 2
3759 5
3771 5
3760
3772
3761 $ cd ..
3773 $ cd ..
3762
3774
3763 test author/desc/keyword in problematic encoding
3775 test author/desc/keyword in problematic encoding
3764 # unicode: cp932:
3776 # unicode: cp932:
3765 # u30A2 0x83 0x41(= 'A')
3777 # u30A2 0x83 0x41(= 'A')
3766 # u30C2 0x83 0x61(= 'a')
3778 # u30C2 0x83 0x61(= 'a')
3767
3779
3768 $ hg init problematicencoding
3780 $ hg init problematicencoding
3769 $ cd problematicencoding
3781 $ cd problematicencoding
3770
3782
3771 $ python > setup.sh <<EOF
3783 $ python > setup.sh <<EOF
3772 > print u'''
3784 > print u'''
3773 > echo a > text
3785 > echo a > text
3774 > hg add text
3786 > hg add text
3775 > hg --encoding utf-8 commit -u '\u30A2' -m none
3787 > hg --encoding utf-8 commit -u '\u30A2' -m none
3776 > echo b > text
3788 > echo b > text
3777 > hg --encoding utf-8 commit -u '\u30C2' -m none
3789 > hg --encoding utf-8 commit -u '\u30C2' -m none
3778 > echo c > text
3790 > echo c > text
3779 > hg --encoding utf-8 commit -u none -m '\u30A2'
3791 > hg --encoding utf-8 commit -u none -m '\u30A2'
3780 > echo d > text
3792 > echo d > text
3781 > hg --encoding utf-8 commit -u none -m '\u30C2'
3793 > hg --encoding utf-8 commit -u none -m '\u30C2'
3782 > '''.encode('utf-8')
3794 > '''.encode('utf-8')
3783 > EOF
3795 > EOF
3784 $ sh < setup.sh
3796 $ sh < setup.sh
3785
3797
3786 test in problematic encoding
3798 test in problematic encoding
3787 $ python > test.sh <<EOF
3799 $ python > test.sh <<EOF
3788 > print u'''
3800 > print u'''
3789 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3801 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
3790 > echo ====
3802 > echo ====
3791 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3803 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
3792 > echo ====
3804 > echo ====
3793 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3805 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
3794 > echo ====
3806 > echo ====
3795 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3807 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
3796 > echo ====
3808 > echo ====
3797 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3809 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
3798 > echo ====
3810 > echo ====
3799 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3811 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
3800 > '''.encode('cp932')
3812 > '''.encode('cp932')
3801 > EOF
3813 > EOF
3802 $ sh < test.sh
3814 $ sh < test.sh
3803 0
3815 0
3804 ====
3816 ====
3805 1
3817 1
3806 ====
3818 ====
3807 2
3819 2
3808 ====
3820 ====
3809 3
3821 3
3810 ====
3822 ====
3811 0
3823 0
3812 2
3824 2
3813 ====
3825 ====
3814 1
3826 1
3815 3
3827 3
3816
3828
3817 test error message of bad revset
3829 test error message of bad revset
3818 $ hg log -r 'foo\\'
3830 $ hg log -r 'foo\\'
3819 hg: parse error at 3: syntax error in revset 'foo\\'
3831 hg: parse error at 3: syntax error in revset 'foo\\'
3820 [255]
3832 [255]
3821
3833
3822 $ cd ..
3834 $ cd ..
3823
3835
3824 Test that revset predicate of extension isn't loaded at failure of
3836 Test that revset predicate of extension isn't loaded at failure of
3825 loading it
3837 loading it
3826
3838
3827 $ cd repo
3839 $ cd repo
3828
3840
3829 $ cat <<EOF > $TESTTMP/custompredicate.py
3841 $ cat <<EOF > $TESTTMP/custompredicate.py
3830 > from mercurial import error, registrar, revset
3842 > from mercurial import error, registrar, revset
3831 >
3843 >
3832 > revsetpredicate = registrar.revsetpredicate()
3844 > revsetpredicate = registrar.revsetpredicate()
3833 >
3845 >
3834 > @revsetpredicate('custom1()')
3846 > @revsetpredicate('custom1()')
3835 > def custom1(repo, subset, x):
3847 > def custom1(repo, subset, x):
3836 > return revset.baseset([1])
3848 > return revset.baseset([1])
3837 >
3849 >
3838 > raise error.Abort('intentional failure of loading extension')
3850 > raise error.Abort('intentional failure of loading extension')
3839 > EOF
3851 > EOF
3840 $ cat <<EOF > .hg/hgrc
3852 $ cat <<EOF > .hg/hgrc
3841 > [extensions]
3853 > [extensions]
3842 > custompredicate = $TESTTMP/custompredicate.py
3854 > custompredicate = $TESTTMP/custompredicate.py
3843 > EOF
3855 > EOF
3844
3856
3845 $ hg debugrevspec "custom1()"
3857 $ hg debugrevspec "custom1()"
3846 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3858 *** failed to import extension custompredicate from $TESTTMP/custompredicate.py: intentional failure of loading extension
3847 hg: parse error: unknown identifier: custom1
3859 hg: parse error: unknown identifier: custom1
3848 [255]
3860 [255]
3849
3861
3850 $ cd ..
3862 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now