##// END OF EJS Templates
fileset: optimize 'x and not y' to 'x - y'...
Yuya Nishihara -
r38868:ca4de8ba default
parent child Browse files
Show More
@@ -1,220 +1,223
1 # filesetlang.py - parser, tokenizer and utility for file set language
1 # filesetlang.py - parser, tokenizer and utility for file set language
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 from .i18n import _
10 from .i18n import _
11 from . import (
11 from . import (
12 error,
12 error,
13 parser,
13 parser,
14 pycompat,
14 pycompat,
15 )
15 )
16
16
17 elements = {
17 elements = {
18 # token-type: binding-strength, primary, prefix, infix, suffix
18 # token-type: binding-strength, primary, prefix, infix, suffix
19 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
19 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
20 ":": (15, None, None, ("kindpat", 15), None),
20 ":": (15, None, None, ("kindpat", 15), None),
21 "-": (5, None, ("negate", 19), ("minus", 5), None),
21 "-": (5, None, ("negate", 19), ("minus", 5), None),
22 "not": (10, None, ("not", 10), None, None),
22 "not": (10, None, ("not", 10), None, None),
23 "!": (10, None, ("not", 10), None, None),
23 "!": (10, None, ("not", 10), None, None),
24 "and": (5, None, None, ("and", 5), None),
24 "and": (5, None, None, ("and", 5), None),
25 "&": (5, None, None, ("and", 5), None),
25 "&": (5, None, None, ("and", 5), None),
26 "or": (4, None, None, ("or", 4), None),
26 "or": (4, None, None, ("or", 4), None),
27 "|": (4, None, None, ("or", 4), None),
27 "|": (4, None, None, ("or", 4), None),
28 "+": (4, None, None, ("or", 4), None),
28 "+": (4, None, None, ("or", 4), None),
29 ",": (2, None, None, ("list", 2), None),
29 ",": (2, None, None, ("list", 2), None),
30 ")": (0, None, None, None, None),
30 ")": (0, None, None, None, None),
31 "symbol": (0, "symbol", None, None, None),
31 "symbol": (0, "symbol", None, None, None),
32 "string": (0, "string", None, None, None),
32 "string": (0, "string", None, None, None),
33 "end": (0, None, None, None, None),
33 "end": (0, None, None, None, None),
34 }
34 }
35
35
36 keywords = {'and', 'or', 'not'}
36 keywords = {'and', 'or', 'not'}
37
37
38 symbols = {}
38 symbols = {}
39
39
40 globchars = ".*{}[]?/\\_"
40 globchars = ".*{}[]?/\\_"
41
41
42 def tokenize(program):
42 def tokenize(program):
43 pos, l = 0, len(program)
43 pos, l = 0, len(program)
44 program = pycompat.bytestr(program)
44 program = pycompat.bytestr(program)
45 while pos < l:
45 while pos < l:
46 c = program[pos]
46 c = program[pos]
47 if c.isspace(): # skip inter-token whitespace
47 if c.isspace(): # skip inter-token whitespace
48 pass
48 pass
49 elif c in "(),-:|&+!": # handle simple operators
49 elif c in "(),-:|&+!": # handle simple operators
50 yield (c, None, pos)
50 yield (c, None, pos)
51 elif (c in '"\'' or c == 'r' and
51 elif (c in '"\'' or c == 'r' and
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 if c == 'r':
53 if c == 'r':
54 pos += 1
54 pos += 1
55 c = program[pos]
55 c = program[pos]
56 decode = lambda x: x
56 decode = lambda x: x
57 else:
57 else:
58 decode = parser.unescapestr
58 decode = parser.unescapestr
59 pos += 1
59 pos += 1
60 s = pos
60 s = pos
61 while pos < l: # find closing quote
61 while pos < l: # find closing quote
62 d = program[pos]
62 d = program[pos]
63 if d == '\\': # skip over escaped characters
63 if d == '\\': # skip over escaped characters
64 pos += 2
64 pos += 2
65 continue
65 continue
66 if d == c:
66 if d == c:
67 yield ('string', decode(program[s:pos]), s)
67 yield ('string', decode(program[s:pos]), s)
68 break
68 break
69 pos += 1
69 pos += 1
70 else:
70 else:
71 raise error.ParseError(_("unterminated string"), s)
71 raise error.ParseError(_("unterminated string"), s)
72 elif c.isalnum() or c in globchars or ord(c) > 127:
72 elif c.isalnum() or c in globchars or ord(c) > 127:
73 # gather up a symbol/keyword
73 # gather up a symbol/keyword
74 s = pos
74 s = pos
75 pos += 1
75 pos += 1
76 while pos < l: # find end of symbol
76 while pos < l: # find end of symbol
77 d = program[pos]
77 d = program[pos]
78 if not (d.isalnum() or d in globchars or ord(d) > 127):
78 if not (d.isalnum() or d in globchars or ord(d) > 127):
79 break
79 break
80 pos += 1
80 pos += 1
81 sym = program[s:pos]
81 sym = program[s:pos]
82 if sym in keywords: # operator keywords
82 if sym in keywords: # operator keywords
83 yield (sym, None, s)
83 yield (sym, None, s)
84 else:
84 else:
85 yield ('symbol', sym, s)
85 yield ('symbol', sym, s)
86 pos -= 1
86 pos -= 1
87 else:
87 else:
88 raise error.ParseError(_("syntax error"), pos)
88 raise error.ParseError(_("syntax error"), pos)
89 pos += 1
89 pos += 1
90 yield ('end', None, pos)
90 yield ('end', None, pos)
91
91
92 def parse(expr):
92 def parse(expr):
93 p = parser.parser(elements)
93 p = parser.parser(elements)
94 tree, pos = p.parse(tokenize(expr))
94 tree, pos = p.parse(tokenize(expr))
95 if pos != len(expr):
95 if pos != len(expr):
96 raise error.ParseError(_("invalid token"), pos)
96 raise error.ParseError(_("invalid token"), pos)
97 return parser.simplifyinfixops(tree, {'list', 'or'})
97 return parser.simplifyinfixops(tree, {'list', 'or'})
98
98
99 def getsymbol(x):
99 def getsymbol(x):
100 if x and x[0] == 'symbol':
100 if x and x[0] == 'symbol':
101 return x[1]
101 return x[1]
102 raise error.ParseError(_('not a symbol'))
102 raise error.ParseError(_('not a symbol'))
103
103
104 def getstring(x, err):
104 def getstring(x, err):
105 if x and (x[0] == 'string' or x[0] == 'symbol'):
105 if x and (x[0] == 'string' or x[0] == 'symbol'):
106 return x[1]
106 return x[1]
107 raise error.ParseError(err)
107 raise error.ParseError(err)
108
108
109 def getkindpat(x, y, allkinds, err):
109 def getkindpat(x, y, allkinds, err):
110 kind = getsymbol(x)
110 kind = getsymbol(x)
111 pat = getstring(y, err)
111 pat = getstring(y, err)
112 if kind not in allkinds:
112 if kind not in allkinds:
113 raise error.ParseError(_("invalid pattern kind: %s") % kind)
113 raise error.ParseError(_("invalid pattern kind: %s") % kind)
114 return '%s:%s' % (kind, pat)
114 return '%s:%s' % (kind, pat)
115
115
116 def getpattern(x, allkinds, err):
116 def getpattern(x, allkinds, err):
117 if x and x[0] == 'kindpat':
117 if x and x[0] == 'kindpat':
118 return getkindpat(x[1], x[2], allkinds, err)
118 return getkindpat(x[1], x[2], allkinds, err)
119 return getstring(x, err)
119 return getstring(x, err)
120
120
121 def getlist(x):
121 def getlist(x):
122 if not x:
122 if not x:
123 return []
123 return []
124 if x[0] == 'list':
124 if x[0] == 'list':
125 return list(x[1:])
125 return list(x[1:])
126 return [x]
126 return [x]
127
127
128 def getargs(x, min, max, err):
128 def getargs(x, min, max, err):
129 l = getlist(x)
129 l = getlist(x)
130 if len(l) < min or len(l) > max:
130 if len(l) < min or len(l) > max:
131 raise error.ParseError(err)
131 raise error.ParseError(err)
132 return l
132 return l
133
133
134 def _analyze(x):
134 def _analyze(x):
135 if x is None:
135 if x is None:
136 return x
136 return x
137
137
138 op = x[0]
138 op = x[0]
139 if op in {'string', 'symbol'}:
139 if op in {'string', 'symbol'}:
140 return x
140 return x
141 if op == 'kindpat':
141 if op == 'kindpat':
142 getsymbol(x[1]) # kind must be a symbol
142 getsymbol(x[1]) # kind must be a symbol
143 t = _analyze(x[2])
143 t = _analyze(x[2])
144 return (op, x[1], t)
144 return (op, x[1], t)
145 if op == 'group':
145 if op == 'group':
146 return _analyze(x[1])
146 return _analyze(x[1])
147 if op == 'negate':
147 if op == 'negate':
148 raise error.ParseError(_("can't use negate operator in this context"))
148 raise error.ParseError(_("can't use negate operator in this context"))
149 if op == 'not':
149 if op == 'not':
150 t = _analyze(x[1])
150 t = _analyze(x[1])
151 return (op, t)
151 return (op, t)
152 if op in {'and', 'minus'}:
152 if op == 'and':
153 ta = _analyze(x[1])
153 ta = _analyze(x[1])
154 tb = _analyze(x[2])
154 tb = _analyze(x[2])
155 return (op, ta, tb)
155 return (op, ta, tb)
156 if op == 'minus':
157 return _analyze(('and', x[1], ('not', x[2])))
156 if op in {'list', 'or'}:
158 if op in {'list', 'or'}:
157 ts = tuple(_analyze(y) for y in x[1:])
159 ts = tuple(_analyze(y) for y in x[1:])
158 return (op,) + ts
160 return (op,) + ts
159 if op == 'func':
161 if op == 'func':
160 getsymbol(x[1]) # function name must be a symbol
162 getsymbol(x[1]) # function name must be a symbol
161 ta = _analyze(x[2])
163 ta = _analyze(x[2])
162 return (op, x[1], ta)
164 return (op, x[1], ta)
163 raise error.ProgrammingError('invalid operator %r' % op)
165 raise error.ProgrammingError('invalid operator %r' % op)
164
166
165 def analyze(x):
167 def analyze(x):
166 """Transform raw parsed tree to evaluatable tree which can be fed to
168 """Transform raw parsed tree to evaluatable tree which can be fed to
167 optimize() or getmatch()
169 optimize() or getmatch()
168
170
169 All pseudo operations should be mapped to real operations or functions
171 All pseudo operations should be mapped to real operations or functions
170 defined in methods or symbols table respectively.
172 defined in methods or symbols table respectively.
171 """
173 """
172 return _analyze(x)
174 return _analyze(x)
173
175
176 def _optimizeandops(op, ta, tb):
177 if tb is not None and tb[0] == 'not':
178 return ('minus', ta, tb[1])
179 return (op, ta, tb)
180
174 def _optimize(x):
181 def _optimize(x):
175 if x is None:
182 if x is None:
176 return 0, x
183 return 0, x
177
184
178 op = x[0]
185 op = x[0]
179 if op in {'string', 'symbol'}:
186 if op in {'string', 'symbol'}:
180 return 0.5, x
187 return 0.5, x
181 if op == 'kindpat':
188 if op == 'kindpat':
182 w, t = _optimize(x[2])
189 w, t = _optimize(x[2])
183 return w, (op, x[1], t)
190 return w, (op, x[1], t)
184 if op == 'not':
191 if op == 'not':
185 w, t = _optimize(x[1])
192 w, t = _optimize(x[1])
186 return w, (op, t)
193 return w, (op, t)
187 if op == 'and':
194 if op == 'and':
188 wa, ta = _optimize(x[1])
195 wa, ta = _optimize(x[1])
189 wb, tb = _optimize(x[2])
196 wb, tb = _optimize(x[2])
190 if wa <= wb:
197 if wa <= wb:
191 return wa, (op, ta, tb)
198 return wa, _optimizeandops(op, ta, tb)
192 else:
199 else:
193 return wb, (op, tb, ta)
200 return wb, _optimizeandops(op, tb, ta)
194 if op == 'minus':
195 wa, ta = _optimize(x[1])
196 wb, tb = _optimize(x[2])
197 return max(wa, wb), (op, ta, tb)
198 if op == 'or':
201 if op == 'or':
199 ws, ts = zip(*(_optimize(y) for y in x[1:]))
202 ws, ts = zip(*(_optimize(y) for y in x[1:]))
200 return max(ws), (op,) + ts
203 return max(ws), (op,) + ts
201 if op == 'list':
204 if op == 'list':
202 ws, ts = zip(*(_optimize(y) for y in x[1:]))
205 ws, ts = zip(*(_optimize(y) for y in x[1:]))
203 return sum(ws), (op,) + ts
206 return sum(ws), (op,) + ts
204 if op == 'func':
207 if op == 'func':
205 f = getsymbol(x[1])
208 f = getsymbol(x[1])
206 w = getattr(symbols.get(f), '_weight', 1)
209 w = getattr(symbols.get(f), '_weight', 1)
207 wa, ta = _optimize(x[2])
210 wa, ta = _optimize(x[2])
208 return w + wa, (op, x[1], ta)
211 return w + wa, (op, x[1], ta)
209 raise error.ProgrammingError('invalid operator %r' % op)
212 raise error.ProgrammingError('invalid operator %r' % op)
210
213
211 def optimize(x):
214 def optimize(x):
212 """Reorder/rewrite evaluatable tree for optimization
215 """Reorder/rewrite evaluatable tree for optimization
213
216
214 All pseudo operations should be transformed beforehand.
217 All pseudo operations should be transformed beforehand.
215 """
218 """
216 _w, t = _optimize(x)
219 _w, t = _optimize(x)
217 return t
220 return t
218
221
219 def prettyformat(tree):
222 def prettyformat(tree):
220 return parser.prettyformat(tree, ('string', 'symbol'))
223 return parser.prettyformat(tree, ('string', 'symbol'))
@@ -1,778 +1,845
1 $ fileset() {
1 $ fileset() {
2 > hg debugfileset --all-files "$@"
2 > hg debugfileset --all-files "$@"
3 > }
3 > }
4
4
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7 $ echo a > a1
7 $ echo a > a1
8 $ echo a > a2
8 $ echo a > a2
9 $ echo b > b1
9 $ echo b > b1
10 $ echo b > b2
10 $ echo b > b2
11 $ hg ci -Am addfiles
11 $ hg ci -Am addfiles
12 adding a1
12 adding a1
13 adding a2
13 adding a2
14 adding b1
14 adding b1
15 adding b2
15 adding b2
16
16
17 Test operators and basic patterns
17 Test operators and basic patterns
18
18
19 $ fileset -v a1
19 $ fileset -v a1
20 (symbol 'a1')
20 (symbol 'a1')
21 * matcher:
21 * matcher:
22 <patternmatcher patterns='(?:a1$)'>
22 <patternmatcher patterns='(?:a1$)'>
23 a1
23 a1
24 $ fileset -v 'a*'
24 $ fileset -v 'a*'
25 (symbol 'a*')
25 (symbol 'a*')
26 * matcher:
26 * matcher:
27 <patternmatcher patterns='(?:a[^/]*$)'>
27 <patternmatcher patterns='(?:a[^/]*$)'>
28 a1
28 a1
29 a2
29 a2
30 $ fileset -v '"re:a\d"'
30 $ fileset -v '"re:a\d"'
31 (string 're:a\\d')
31 (string 're:a\\d')
32 * matcher:
32 * matcher:
33 <patternmatcher patterns='(?:a\\d)'>
33 <patternmatcher patterns='(?:a\\d)'>
34 a1
34 a1
35 a2
35 a2
36 $ fileset -v '!re:"a\d"'
36 $ fileset -v '!re:"a\d"'
37 (not
37 (not
38 (kindpat
38 (kindpat
39 (symbol 're')
39 (symbol 're')
40 (string 'a\\d')))
40 (string 'a\\d')))
41 * matcher:
41 * matcher:
42 <predicatenmatcher
42 <predicatenmatcher
43 pred=<not
43 pred=<not
44 <patternmatcher patterns='(?:a\\d)'>>>
44 <patternmatcher patterns='(?:a\\d)'>>>
45 b1
45 b1
46 b2
46 b2
47 $ fileset -v 'path:a1 or glob:b?'
47 $ fileset -v 'path:a1 or glob:b?'
48 (or
48 (or
49 (kindpat
49 (kindpat
50 (symbol 'path')
50 (symbol 'path')
51 (symbol 'a1'))
51 (symbol 'a1'))
52 (kindpat
52 (kindpat
53 (symbol 'glob')
53 (symbol 'glob')
54 (symbol 'b?')))
54 (symbol 'b?')))
55 * matcher:
55 * matcher:
56 <unionmatcher matchers=[
56 <unionmatcher matchers=[
57 <patternmatcher patterns='(?:a1(?:/|$))'>,
57 <patternmatcher patterns='(?:a1(?:/|$))'>,
58 <patternmatcher patterns='(?:b.$)'>]>
58 <patternmatcher patterns='(?:b.$)'>]>
59 a1
59 a1
60 b1
60 b1
61 b2
61 b2
62 $ fileset -v --no-show-matcher 'a1 or a2'
62 $ fileset -v --no-show-matcher 'a1 or a2'
63 (or
63 (or
64 (symbol 'a1')
64 (symbol 'a1')
65 (symbol 'a2'))
65 (symbol 'a2'))
66 a1
66 a1
67 a2
67 a2
68 $ fileset 'a1 | a2'
68 $ fileset 'a1 | a2'
69 a1
69 a1
70 a2
70 a2
71 $ fileset 'a* and "*1"'
71 $ fileset 'a* and "*1"'
72 a1
72 a1
73 $ fileset 'a* & "*1"'
73 $ fileset 'a* & "*1"'
74 a1
74 a1
75 $ fileset 'not (r"a*")'
75 $ fileset 'not (r"a*")'
76 b1
76 b1
77 b2
77 b2
78 $ fileset '! ("a*")'
78 $ fileset '! ("a*")'
79 b1
79 b1
80 b2
80 b2
81 $ fileset 'a* - a1'
81 $ fileset 'a* - a1'
82 a2
82 a2
83 $ fileset 'a_b'
83 $ fileset 'a_b'
84 $ fileset '"\xy"'
84 $ fileset '"\xy"'
85 hg: parse error: invalid \x escape* (glob)
85 hg: parse error: invalid \x escape* (glob)
86 [255]
86 [255]
87
87
88 Test invalid syntax
88 Test invalid syntax
89
89
90 $ fileset -v '"added"()'
90 $ fileset -v '"added"()'
91 (func
91 (func
92 (string 'added')
92 (string 'added')
93 None)
93 None)
94 hg: parse error: not a symbol
94 hg: parse error: not a symbol
95 [255]
95 [255]
96 $ fileset -v '()()'
96 $ fileset -v '()()'
97 (func
97 (func
98 (group
98 (group
99 None)
99 None)
100 None)
100 None)
101 hg: parse error: not a symbol
101 hg: parse error: not a symbol
102 [255]
102 [255]
103 $ fileset -v -- '-x'
103 $ fileset -v -- '-x'
104 (negate
104 (negate
105 (symbol 'x'))
105 (symbol 'x'))
106 hg: parse error: can't use negate operator in this context
106 hg: parse error: can't use negate operator in this context
107 [255]
107 [255]
108 $ fileset -v -- '-()'
108 $ fileset -v -- '-()'
109 (negate
109 (negate
110 (group
110 (group
111 None))
111 None))
112 hg: parse error: can't use negate operator in this context
112 hg: parse error: can't use negate operator in this context
113 [255]
113 [255]
114 $ fileset -p parsed 'a, b, c'
114 $ fileset -p parsed 'a, b, c'
115 * parsed:
115 * parsed:
116 (list
116 (list
117 (symbol 'a')
117 (symbol 'a')
118 (symbol 'b')
118 (symbol 'b')
119 (symbol 'c'))
119 (symbol 'c'))
120 hg: parse error: can't use a list in this context
120 hg: parse error: can't use a list in this context
121 (see 'hg help "filesets.x or y"')
121 (see 'hg help "filesets.x or y"')
122 [255]
122 [255]
123
123
124 $ fileset '"path":.'
124 $ fileset '"path":.'
125 hg: parse error: not a symbol
125 hg: parse error: not a symbol
126 [255]
126 [255]
127 $ fileset 'path:foo bar'
127 $ fileset 'path:foo bar'
128 hg: parse error at 9: invalid token
128 hg: parse error at 9: invalid token
129 [255]
129 [255]
130 $ fileset 'foo:bar:baz'
130 $ fileset 'foo:bar:baz'
131 hg: parse error: not a symbol
131 hg: parse error: not a symbol
132 [255]
132 [255]
133 $ fileset 'foo:bar()'
133 $ fileset 'foo:bar()'
134 hg: parse error: pattern must be a string
134 hg: parse error: pattern must be a string
135 [255]
135 [255]
136 $ fileset 'foo:bar'
136 $ fileset 'foo:bar'
137 hg: parse error: invalid pattern kind: foo
137 hg: parse error: invalid pattern kind: foo
138 [255]
138 [255]
139
139
140 Show parsed tree at stages:
140 Show parsed tree at stages:
141
141
142 $ fileset -p unknown a
142 $ fileset -p unknown a
143 abort: invalid stage name: unknown
143 abort: invalid stage name: unknown
144 [255]
144 [255]
145
145
146 $ fileset -p parsed 'path:a1 or glob:b?'
146 $ fileset -p parsed 'path:a1 or glob:b?'
147 * parsed:
147 * parsed:
148 (or
148 (or
149 (kindpat
149 (kindpat
150 (symbol 'path')
150 (symbol 'path')
151 (symbol 'a1'))
151 (symbol 'a1'))
152 (kindpat
152 (kindpat
153 (symbol 'glob')
153 (symbol 'glob')
154 (symbol 'b?')))
154 (symbol 'b?')))
155 a1
155 a1
156 b1
156 b1
157 b2
157 b2
158
158
159 $ fileset -p all -s 'a1 or a2 or (grep("b") & clean())'
159 $ fileset -p all -s 'a1 or a2 or (grep("b") & clean())'
160 * parsed:
160 * parsed:
161 (or
161 (or
162 (symbol 'a1')
162 (symbol 'a1')
163 (symbol 'a2')
163 (symbol 'a2')
164 (group
164 (group
165 (and
165 (and
166 (func
166 (func
167 (symbol 'grep')
167 (symbol 'grep')
168 (string 'b'))
168 (string 'b'))
169 (func
169 (func
170 (symbol 'clean')
170 (symbol 'clean')
171 None))))
171 None))))
172 * analyzed:
172 * analyzed:
173 (or
173 (or
174 (symbol 'a1')
174 (symbol 'a1')
175 (symbol 'a2')
175 (symbol 'a2')
176 (and
176 (and
177 (func
177 (func
178 (symbol 'grep')
178 (symbol 'grep')
179 (string 'b'))
179 (string 'b'))
180 (func
180 (func
181 (symbol 'clean')
181 (symbol 'clean')
182 None)))
182 None)))
183 * optimized:
183 * optimized:
184 (or
184 (or
185 (symbol 'a1')
185 (symbol 'a1')
186 (symbol 'a2')
186 (symbol 'a2')
187 (and
187 (and
188 (func
188 (func
189 (symbol 'clean')
189 (symbol 'clean')
190 None)
190 None)
191 (func
191 (func
192 (symbol 'grep')
192 (symbol 'grep')
193 (string 'b'))))
193 (string 'b'))))
194 * matcher:
194 * matcher:
195 <unionmatcher matchers=[
195 <unionmatcher matchers=[
196 <patternmatcher patterns='(?:a1$)'>,
196 <patternmatcher patterns='(?:a1$)'>,
197 <patternmatcher patterns='(?:a2$)'>,
197 <patternmatcher patterns='(?:a2$)'>,
198 <intersectionmatcher
198 <intersectionmatcher
199 m1=<predicatenmatcher pred=clean>,
199 m1=<predicatenmatcher pred=clean>,
200 m2=<predicatenmatcher pred=grep('b')>>]>
200 m2=<predicatenmatcher pred=grep('b')>>]>
201 a1
201 a1
202 a2
202 a2
203 b1
203 b1
204 b2
204 b2
205
205
206 Use differencematcher for 'x and not y':
207
208 $ fileset -p optimized -s 'a* and not a1'
209 * optimized:
210 (minus
211 (symbol 'a*')
212 (symbol 'a1'))
213 * matcher:
214 <differencematcher
215 m1=<patternmatcher patterns='(?:a[^/]*$)'>,
216 m2=<patternmatcher patterns='(?:a1$)'>>
217 a2
218
219 $ fileset -p optimized -s '!binary() and a*'
220 * optimized:
221 (minus
222 (symbol 'a*')
223 (func
224 (symbol 'binary')
225 None))
226 * matcher:
227 <differencematcher
228 m1=<patternmatcher patterns='(?:a[^/]*$)'>,
229 m2=<predicatenmatcher pred=binary>>
230 a1
231 a2
232
233 'x - y' is rewritten to 'x and not y' first so the operands can be reordered:
234
235 $ fileset -p analyzed -p optimized -s 'a* - a1'
236 * analyzed:
237 (and
238 (symbol 'a*')
239 (not
240 (symbol 'a1')))
241 * optimized:
242 (minus
243 (symbol 'a*')
244 (symbol 'a1'))
245 * matcher:
246 <differencematcher
247 m1=<patternmatcher patterns='(?:a[^/]*$)'>,
248 m2=<patternmatcher patterns='(?:a1$)'>>
249 a2
250
251 $ fileset -p analyzed -p optimized -s 'binary() - a*'
252 * analyzed:
253 (and
254 (func
255 (symbol 'binary')
256 None)
257 (not
258 (symbol 'a*')))
259 * optimized:
260 (and
261 (not
262 (symbol 'a*'))
263 (func
264 (symbol 'binary')
265 None))
266 * matcher:
267 <intersectionmatcher
268 m1=<predicatenmatcher
269 pred=<not
270 <patternmatcher patterns='(?:a[^/]*$)'>>>,
271 m2=<predicatenmatcher pred=binary>>
272
206 Test files status
273 Test files status
207
274
208 $ rm a1
275 $ rm a1
209 $ hg rm a2
276 $ hg rm a2
210 $ echo b >> b2
277 $ echo b >> b2
211 $ hg cp b1 c1
278 $ hg cp b1 c1
212 $ echo c > c2
279 $ echo c > c2
213 $ echo c > c3
280 $ echo c > c3
214 $ cat > .hgignore <<EOF
281 $ cat > .hgignore <<EOF
215 > \.hgignore
282 > \.hgignore
216 > 2$
283 > 2$
217 > EOF
284 > EOF
218 $ fileset 'modified()'
285 $ fileset 'modified()'
219 b2
286 b2
220 $ fileset 'added()'
287 $ fileset 'added()'
221 c1
288 c1
222 $ fileset 'removed()'
289 $ fileset 'removed()'
223 a2
290 a2
224 $ fileset 'deleted()'
291 $ fileset 'deleted()'
225 a1
292 a1
226 $ fileset 'missing()'
293 $ fileset 'missing()'
227 a1
294 a1
228 $ fileset 'unknown()'
295 $ fileset 'unknown()'
229 c3
296 c3
230 $ fileset 'ignored()'
297 $ fileset 'ignored()'
231 .hgignore
298 .hgignore
232 c2
299 c2
233 $ fileset 'hgignore()'
300 $ fileset 'hgignore()'
234 .hgignore
301 .hgignore
235 a2
302 a2
236 b2
303 b2
237 c2
304 c2
238 $ fileset 'clean()'
305 $ fileset 'clean()'
239 b1
306 b1
240 $ fileset 'copied()'
307 $ fileset 'copied()'
241 c1
308 c1
242
309
243 Test files status in different revisions
310 Test files status in different revisions
244
311
245 $ hg status -m
312 $ hg status -m
246 M b2
313 M b2
247 $ fileset -r0 'revs("wdir()", modified())' --traceback
314 $ fileset -r0 'revs("wdir()", modified())' --traceback
248 b2
315 b2
249 $ hg status -a
316 $ hg status -a
250 A c1
317 A c1
251 $ fileset -r0 'revs("wdir()", added())'
318 $ fileset -r0 'revs("wdir()", added())'
252 c1
319 c1
253 $ hg status --change 0 -a
320 $ hg status --change 0 -a
254 A a1
321 A a1
255 A a2
322 A a2
256 A b1
323 A b1
257 A b2
324 A b2
258 $ hg status -mru
325 $ hg status -mru
259 M b2
326 M b2
260 R a2
327 R a2
261 ? c3
328 ? c3
262 $ fileset -r0 'added() and revs("wdir()", modified() or removed() or unknown())'
329 $ fileset -r0 'added() and revs("wdir()", modified() or removed() or unknown())'
263 a2
330 a2
264 b2
331 b2
265 $ fileset -r0 'added() or revs("wdir()", added())'
332 $ fileset -r0 'added() or revs("wdir()", added())'
266 a1
333 a1
267 a2
334 a2
268 b1
335 b1
269 b2
336 b2
270 c1
337 c1
271
338
272 Test files properties
339 Test files properties
273
340
274 >>> open('bin', 'wb').write(b'\0a') and None
341 >>> open('bin', 'wb').write(b'\0a') and None
275 $ fileset 'binary()'
342 $ fileset 'binary()'
276 bin
343 bin
277 $ fileset 'binary() and unknown()'
344 $ fileset 'binary() and unknown()'
278 bin
345 bin
279 $ echo '^bin$' >> .hgignore
346 $ echo '^bin$' >> .hgignore
280 $ fileset 'binary() and ignored()'
347 $ fileset 'binary() and ignored()'
281 bin
348 bin
282 $ hg add bin
349 $ hg add bin
283 $ fileset 'binary()'
350 $ fileset 'binary()'
284 bin
351 bin
285
352
286 $ fileset -p optimized -s 'binary() and b*'
353 $ fileset -p optimized -s 'binary() and b*'
287 * optimized:
354 * optimized:
288 (and
355 (and
289 (symbol 'b*')
356 (symbol 'b*')
290 (func
357 (func
291 (symbol 'binary')
358 (symbol 'binary')
292 None))
359 None))
293 * matcher:
360 * matcher:
294 <intersectionmatcher
361 <intersectionmatcher
295 m1=<patternmatcher patterns='(?:b[^/]*$)'>,
362 m1=<patternmatcher patterns='(?:b[^/]*$)'>,
296 m2=<predicatenmatcher pred=binary>>
363 m2=<predicatenmatcher pred=binary>>
297 bin
364 bin
298
365
299 $ fileset 'grep("b{1}")'
366 $ fileset 'grep("b{1}")'
300 .hgignore
367 .hgignore
301 b1
368 b1
302 b2
369 b2
303 c1
370 c1
304 $ fileset 'grep("missingparens(")'
371 $ fileset 'grep("missingparens(")'
305 hg: parse error: invalid match pattern: (unbalanced parenthesis|missing \)).* (re)
372 hg: parse error: invalid match pattern: (unbalanced parenthesis|missing \)).* (re)
306 [255]
373 [255]
307
374
308 #if execbit
375 #if execbit
309 $ chmod +x b2
376 $ chmod +x b2
310 $ fileset 'exec()'
377 $ fileset 'exec()'
311 b2
378 b2
312 #endif
379 #endif
313
380
314 #if symlink
381 #if symlink
315 $ ln -s b2 b2link
382 $ ln -s b2 b2link
316 $ fileset 'symlink() and unknown()'
383 $ fileset 'symlink() and unknown()'
317 b2link
384 b2link
318 $ hg add b2link
385 $ hg add b2link
319 #endif
386 #endif
320
387
321 #if no-windows
388 #if no-windows
322 $ echo foo > con.xml
389 $ echo foo > con.xml
323 $ fileset 'not portable()'
390 $ fileset 'not portable()'
324 con.xml
391 con.xml
325 $ hg --config ui.portablefilenames=ignore add con.xml
392 $ hg --config ui.portablefilenames=ignore add con.xml
326 #endif
393 #endif
327
394
328 >>> open('1k', 'wb').write(b' '*1024) and None
395 >>> open('1k', 'wb').write(b' '*1024) and None
329 >>> open('2k', 'wb').write(b' '*2048) and None
396 >>> open('2k', 'wb').write(b' '*2048) and None
330 $ hg add 1k 2k
397 $ hg add 1k 2k
331 $ fileset 'size("bar")'
398 $ fileset 'size("bar")'
332 hg: parse error: couldn't parse size: bar
399 hg: parse error: couldn't parse size: bar
333 [255]
400 [255]
334 $ fileset '(1k, 2k)'
401 $ fileset '(1k, 2k)'
335 hg: parse error: can't use a list in this context
402 hg: parse error: can't use a list in this context
336 (see 'hg help "filesets.x or y"')
403 (see 'hg help "filesets.x or y"')
337 [255]
404 [255]
338 $ fileset 'size(1k)'
405 $ fileset 'size(1k)'
339 1k
406 1k
340 $ fileset '(1k or 2k) and size("< 2k")'
407 $ fileset '(1k or 2k) and size("< 2k")'
341 1k
408 1k
342 $ fileset '(1k or 2k) and size("<=2k")'
409 $ fileset '(1k or 2k) and size("<=2k")'
343 1k
410 1k
344 2k
411 2k
345 $ fileset '(1k or 2k) and size("> 1k")'
412 $ fileset '(1k or 2k) and size("> 1k")'
346 2k
413 2k
347 $ fileset '(1k or 2k) and size(">=1K")'
414 $ fileset '(1k or 2k) and size(">=1K")'
348 1k
415 1k
349 2k
416 2k
350 $ fileset '(1k or 2k) and size(".5KB - 1.5kB")'
417 $ fileset '(1k or 2k) and size(".5KB - 1.5kB")'
351 1k
418 1k
352 $ fileset 'size("1M")'
419 $ fileset 'size("1M")'
353 $ fileset 'size("1 GB")'
420 $ fileset 'size("1 GB")'
354
421
355 Test merge states
422 Test merge states
356
423
357 $ hg ci -m manychanges
424 $ hg ci -m manychanges
358 $ hg file -r . 'set:copied() & modified()'
425 $ hg file -r . 'set:copied() & modified()'
359 [1]
426 [1]
360 $ hg up -C 0
427 $ hg up -C 0
361 * files updated, 0 files merged, * files removed, 0 files unresolved (glob)
428 * files updated, 0 files merged, * files removed, 0 files unresolved (glob)
362 $ echo c >> b2
429 $ echo c >> b2
363 $ hg ci -m diverging b2
430 $ hg ci -m diverging b2
364 created new head
431 created new head
365 $ fileset 'resolved()'
432 $ fileset 'resolved()'
366 $ fileset 'unresolved()'
433 $ fileset 'unresolved()'
367 $ hg merge
434 $ hg merge
368 merging b2
435 merging b2
369 warning: conflicts while merging b2! (edit, then use 'hg resolve --mark')
436 warning: conflicts while merging b2! (edit, then use 'hg resolve --mark')
370 * files updated, 0 files merged, 1 files removed, 1 files unresolved (glob)
437 * files updated, 0 files merged, 1 files removed, 1 files unresolved (glob)
371 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
438 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
372 [1]
439 [1]
373 $ fileset 'resolved()'
440 $ fileset 'resolved()'
374 $ fileset 'unresolved()'
441 $ fileset 'unresolved()'
375 b2
442 b2
376 $ echo e > b2
443 $ echo e > b2
377 $ hg resolve -m b2
444 $ hg resolve -m b2
378 (no more unresolved files)
445 (no more unresolved files)
379 $ fileset 'resolved()'
446 $ fileset 'resolved()'
380 b2
447 b2
381 $ fileset 'unresolved()'
448 $ fileset 'unresolved()'
382 $ hg ci -m merge
449 $ hg ci -m merge
383
450
384 Test subrepo predicate
451 Test subrepo predicate
385
452
386 $ hg init sub
453 $ hg init sub
387 $ echo a > sub/suba
454 $ echo a > sub/suba
388 $ hg -R sub add sub/suba
455 $ hg -R sub add sub/suba
389 $ hg -R sub ci -m sub
456 $ hg -R sub ci -m sub
390 $ echo 'sub = sub' > .hgsub
457 $ echo 'sub = sub' > .hgsub
391 $ hg init sub2
458 $ hg init sub2
392 $ echo b > sub2/b
459 $ echo b > sub2/b
393 $ hg -R sub2 ci -Am sub2
460 $ hg -R sub2 ci -Am sub2
394 adding b
461 adding b
395 $ echo 'sub2 = sub2' >> .hgsub
462 $ echo 'sub2 = sub2' >> .hgsub
396 $ fileset 'subrepo()'
463 $ fileset 'subrepo()'
397 $ hg add .hgsub
464 $ hg add .hgsub
398 $ fileset 'subrepo()'
465 $ fileset 'subrepo()'
399 sub
466 sub
400 sub2
467 sub2
401 $ fileset 'subrepo("sub")'
468 $ fileset 'subrepo("sub")'
402 sub
469 sub
403 $ fileset 'subrepo("glob:*")'
470 $ fileset 'subrepo("glob:*")'
404 sub
471 sub
405 sub2
472 sub2
406 $ hg ci -m subrepo
473 $ hg ci -m subrepo
407
474
408 Test that .hgsubstate is updated as appropriate during a conversion. The
475 Test that .hgsubstate is updated as appropriate during a conversion. The
409 saverev property is enough to alter the hashes of the subrepo.
476 saverev property is enough to alter the hashes of the subrepo.
410
477
411 $ hg init ../converted
478 $ hg init ../converted
412 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
479 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
413 > sub ../converted/sub
480 > sub ../converted/sub
414 initializing destination ../converted/sub repository
481 initializing destination ../converted/sub repository
415 scanning source...
482 scanning source...
416 sorting...
483 sorting...
417 converting...
484 converting...
418 0 sub
485 0 sub
419 $ hg clone -U sub2 ../converted/sub2
486 $ hg clone -U sub2 ../converted/sub2
420 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
487 $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
421 > . ../converted
488 > . ../converted
422 scanning source...
489 scanning source...
423 sorting...
490 sorting...
424 converting...
491 converting...
425 4 addfiles
492 4 addfiles
426 3 manychanges
493 3 manychanges
427 2 diverging
494 2 diverging
428 1 merge
495 1 merge
429 0 subrepo
496 0 subrepo
430 no ".hgsubstate" updates will be made for "sub2"
497 no ".hgsubstate" updates will be made for "sub2"
431 $ hg up -q -R ../converted -r tip
498 $ hg up -q -R ../converted -r tip
432 $ hg --cwd ../converted cat sub/suba sub2/b -r tip
499 $ hg --cwd ../converted cat sub/suba sub2/b -r tip
433 a
500 a
434 b
501 b
435 $ oldnode=`hg log -r tip -T "{node}\n"`
502 $ oldnode=`hg log -r tip -T "{node}\n"`
436 $ newnode=`hg log -R ../converted -r tip -T "{node}\n"`
503 $ newnode=`hg log -R ../converted -r tip -T "{node}\n"`
437 $ [ "$oldnode" != "$newnode" ] || echo "nothing changed"
504 $ [ "$oldnode" != "$newnode" ] || echo "nothing changed"
438
505
439 Test with a revision
506 Test with a revision
440
507
441 $ hg log -G --template '{rev} {desc}\n'
508 $ hg log -G --template '{rev} {desc}\n'
442 @ 4 subrepo
509 @ 4 subrepo
443 |
510 |
444 o 3 merge
511 o 3 merge
445 |\
512 |\
446 | o 2 diverging
513 | o 2 diverging
447 | |
514 | |
448 o | 1 manychanges
515 o | 1 manychanges
449 |/
516 |/
450 o 0 addfiles
517 o 0 addfiles
451
518
452 $ echo unknown > unknown
519 $ echo unknown > unknown
453 $ fileset -r1 'modified()'
520 $ fileset -r1 'modified()'
454 b2
521 b2
455 $ fileset -r1 'added() and c1'
522 $ fileset -r1 'added() and c1'
456 c1
523 c1
457 $ fileset -r1 'removed()'
524 $ fileset -r1 'removed()'
458 a2
525 a2
459 $ fileset -r1 'deleted()'
526 $ fileset -r1 'deleted()'
460 $ fileset -r1 'unknown()'
527 $ fileset -r1 'unknown()'
461 $ fileset -r1 'ignored()'
528 $ fileset -r1 'ignored()'
462 $ fileset -r1 'hgignore()'
529 $ fileset -r1 'hgignore()'
463 .hgignore
530 .hgignore
464 a2
531 a2
465 b2
532 b2
466 bin
533 bin
467 c2
534 c2
468 sub2
535 sub2
469 $ fileset -r1 'binary()'
536 $ fileset -r1 'binary()'
470 bin
537 bin
471 $ fileset -r1 'size(1k)'
538 $ fileset -r1 'size(1k)'
472 1k
539 1k
473 $ fileset -r3 'resolved()'
540 $ fileset -r3 'resolved()'
474 $ fileset -r3 'unresolved()'
541 $ fileset -r3 'unresolved()'
475
542
476 #if execbit
543 #if execbit
477 $ fileset -r1 'exec()'
544 $ fileset -r1 'exec()'
478 b2
545 b2
479 #endif
546 #endif
480
547
481 #if symlink
548 #if symlink
482 $ fileset -r1 'symlink()'
549 $ fileset -r1 'symlink()'
483 b2link
550 b2link
484 #endif
551 #endif
485
552
486 #if no-windows
553 #if no-windows
487 $ fileset -r1 'not portable()'
554 $ fileset -r1 'not portable()'
488 con.xml
555 con.xml
489 $ hg forget 'con.xml'
556 $ hg forget 'con.xml'
490 #endif
557 #endif
491
558
492 $ fileset -r4 'subrepo("re:su.*")'
559 $ fileset -r4 'subrepo("re:su.*")'
493 sub
560 sub
494 sub2
561 sub2
495 $ fileset -r4 'subrepo(re:su.*)'
562 $ fileset -r4 'subrepo(re:su.*)'
496 sub
563 sub
497 sub2
564 sub2
498 $ fileset -r4 'subrepo("sub")'
565 $ fileset -r4 'subrepo("sub")'
499 sub
566 sub
500 $ fileset -r4 'b2 or c1'
567 $ fileset -r4 'b2 or c1'
501 b2
568 b2
502 c1
569 c1
503
570
504 >>> open('dos', 'wb').write(b"dos\r\n") and None
571 >>> open('dos', 'wb').write(b"dos\r\n") and None
505 >>> open('mixed', 'wb').write(b"dos\r\nunix\n") and None
572 >>> open('mixed', 'wb').write(b"dos\r\nunix\n") and None
506 >>> open('mac', 'wb').write(b"mac\r") and None
573 >>> open('mac', 'wb').write(b"mac\r") and None
507 $ hg add dos mixed mac
574 $ hg add dos mixed mac
508
575
509 (remove a1, to examine safety of 'eol' on removed files)
576 (remove a1, to examine safety of 'eol' on removed files)
510 $ rm a1
577 $ rm a1
511
578
512 $ fileset 'eol(dos)'
579 $ fileset 'eol(dos)'
513 dos
580 dos
514 mixed
581 mixed
515 $ fileset 'eol(unix)'
582 $ fileset 'eol(unix)'
516 .hgignore
583 .hgignore
517 .hgsub
584 .hgsub
518 .hgsubstate
585 .hgsubstate
519 b1
586 b1
520 b2
587 b2
521 b2.orig
588 b2.orig
522 c1
589 c1
523 c2
590 c2
524 c3
591 c3
525 con.xml (no-windows !)
592 con.xml (no-windows !)
526 mixed
593 mixed
527 unknown
594 unknown
528 $ fileset 'eol(mac)'
595 $ fileset 'eol(mac)'
529 mac
596 mac
530
597
531 Test safety of 'encoding' on removed files
598 Test safety of 'encoding' on removed files
532
599
533 $ fileset 'encoding("ascii")'
600 $ fileset 'encoding("ascii")'
534 .hgignore
601 .hgignore
535 .hgsub
602 .hgsub
536 .hgsubstate
603 .hgsubstate
537 1k
604 1k
538 2k
605 2k
539 b1
606 b1
540 b2
607 b2
541 b2.orig
608 b2.orig
542 b2link (symlink !)
609 b2link (symlink !)
543 bin
610 bin
544 c1
611 c1
545 c2
612 c2
546 c3
613 c3
547 con.xml (no-windows !)
614 con.xml (no-windows !)
548 dos
615 dos
549 mac
616 mac
550 mixed
617 mixed
551 unknown
618 unknown
552
619
553 Test 'revs(...)'
620 Test 'revs(...)'
554 ================
621 ================
555
622
556 small reminder of the repository state
623 small reminder of the repository state
557
624
558 $ hg log -G
625 $ hg log -G
559 @ changeset: 4:* (glob)
626 @ changeset: 4:* (glob)
560 | tag: tip
627 | tag: tip
561 | user: test
628 | user: test
562 | date: Thu Jan 01 00:00:00 1970 +0000
629 | date: Thu Jan 01 00:00:00 1970 +0000
563 | summary: subrepo
630 | summary: subrepo
564 |
631 |
565 o changeset: 3:* (glob)
632 o changeset: 3:* (glob)
566 |\ parent: 2:55b05bdebf36
633 |\ parent: 2:55b05bdebf36
567 | | parent: 1:* (glob)
634 | | parent: 1:* (glob)
568 | | user: test
635 | | user: test
569 | | date: Thu Jan 01 00:00:00 1970 +0000
636 | | date: Thu Jan 01 00:00:00 1970 +0000
570 | | summary: merge
637 | | summary: merge
571 | |
638 | |
572 | o changeset: 2:55b05bdebf36
639 | o changeset: 2:55b05bdebf36
573 | | parent: 0:8a9576c51c1f
640 | | parent: 0:8a9576c51c1f
574 | | user: test
641 | | user: test
575 | | date: Thu Jan 01 00:00:00 1970 +0000
642 | | date: Thu Jan 01 00:00:00 1970 +0000
576 | | summary: diverging
643 | | summary: diverging
577 | |
644 | |
578 o | changeset: 1:* (glob)
645 o | changeset: 1:* (glob)
579 |/ user: test
646 |/ user: test
580 | date: Thu Jan 01 00:00:00 1970 +0000
647 | date: Thu Jan 01 00:00:00 1970 +0000
581 | summary: manychanges
648 | summary: manychanges
582 |
649 |
583 o changeset: 0:8a9576c51c1f
650 o changeset: 0:8a9576c51c1f
584 user: test
651 user: test
585 date: Thu Jan 01 00:00:00 1970 +0000
652 date: Thu Jan 01 00:00:00 1970 +0000
586 summary: addfiles
653 summary: addfiles
587
654
588 $ hg status --change 0
655 $ hg status --change 0
589 A a1
656 A a1
590 A a2
657 A a2
591 A b1
658 A b1
592 A b2
659 A b2
593 $ hg status --change 1
660 $ hg status --change 1
594 M b2
661 M b2
595 A 1k
662 A 1k
596 A 2k
663 A 2k
597 A b2link (no-windows !)
664 A b2link (no-windows !)
598 A bin
665 A bin
599 A c1
666 A c1
600 A con.xml (no-windows !)
667 A con.xml (no-windows !)
601 R a2
668 R a2
602 $ hg status --change 2
669 $ hg status --change 2
603 M b2
670 M b2
604 $ hg status --change 3
671 $ hg status --change 3
605 M b2
672 M b2
606 A 1k
673 A 1k
607 A 2k
674 A 2k
608 A b2link (no-windows !)
675 A b2link (no-windows !)
609 A bin
676 A bin
610 A c1
677 A c1
611 A con.xml (no-windows !)
678 A con.xml (no-windows !)
612 R a2
679 R a2
613 $ hg status --change 4
680 $ hg status --change 4
614 A .hgsub
681 A .hgsub
615 A .hgsubstate
682 A .hgsubstate
616 $ hg status
683 $ hg status
617 A dos
684 A dos
618 A mac
685 A mac
619 A mixed
686 A mixed
620 R con.xml (no-windows !)
687 R con.xml (no-windows !)
621 ! a1
688 ! a1
622 ? b2.orig
689 ? b2.orig
623 ? c3
690 ? c3
624 ? unknown
691 ? unknown
625
692
626 Test files at -r0 should be filtered by files at wdir
693 Test files at -r0 should be filtered by files at wdir
627 -----------------------------------------------------
694 -----------------------------------------------------
628
695
629 $ fileset -r0 'tracked() and revs("wdir()", tracked())'
696 $ fileset -r0 'tracked() and revs("wdir()", tracked())'
630 a1
697 a1
631 b1
698 b1
632 b2
699 b2
633
700
634 Test that "revs()" work at all
701 Test that "revs()" work at all
635 ------------------------------
702 ------------------------------
636
703
637 $ fileset "revs('2', modified())"
704 $ fileset "revs('2', modified())"
638 b2
705 b2
639
706
640 Test that "revs()" work for file missing in the working copy/current context
707 Test that "revs()" work for file missing in the working copy/current context
641 ----------------------------------------------------------------------------
708 ----------------------------------------------------------------------------
642
709
643 (a2 not in working copy)
710 (a2 not in working copy)
644
711
645 $ fileset "revs('0', added())"
712 $ fileset "revs('0', added())"
646 a1
713 a1
647 a2
714 a2
648 b1
715 b1
649 b2
716 b2
650
717
651 (none of the file exist in "0")
718 (none of the file exist in "0")
652
719
653 $ fileset -r 0 "revs('4', added())"
720 $ fileset -r 0 "revs('4', added())"
654 .hgsub
721 .hgsub
655 .hgsubstate
722 .hgsubstate
656
723
657 Call with empty revset
724 Call with empty revset
658 --------------------------
725 --------------------------
659
726
660 $ fileset "revs('2-2', modified())"
727 $ fileset "revs('2-2', modified())"
661
728
662 Call with revset matching multiple revs
729 Call with revset matching multiple revs
663 ---------------------------------------
730 ---------------------------------------
664
731
665 $ fileset "revs('0+4', added())"
732 $ fileset "revs('0+4', added())"
666 .hgsub
733 .hgsub
667 .hgsubstate
734 .hgsubstate
668 a1
735 a1
669 a2
736 a2
670 b1
737 b1
671 b2
738 b2
672
739
673 overlapping set
740 overlapping set
674
741
675 $ fileset "revs('1+2', modified())"
742 $ fileset "revs('1+2', modified())"
676 b2
743 b2
677
744
678 test 'status(...)'
745 test 'status(...)'
679 =================
746 =================
680
747
681 Simple case
748 Simple case
682 -----------
749 -----------
683
750
684 $ fileset "status(3, 4, added())"
751 $ fileset "status(3, 4, added())"
685 .hgsub
752 .hgsub
686 .hgsubstate
753 .hgsubstate
687
754
688 use rev to restrict matched file
755 use rev to restrict matched file
689 -----------------------------------------
756 -----------------------------------------
690
757
691 $ hg status --removed --rev 0 --rev 1
758 $ hg status --removed --rev 0 --rev 1
692 R a2
759 R a2
693 $ fileset "status(0, 1, removed())"
760 $ fileset "status(0, 1, removed())"
694 a2
761 a2
695 $ fileset "tracked() and status(0, 1, removed())"
762 $ fileset "tracked() and status(0, 1, removed())"
696 $ fileset -r 4 "status(0, 1, removed())"
763 $ fileset -r 4 "status(0, 1, removed())"
697 a2
764 a2
698 $ fileset -r 4 "tracked() and status(0, 1, removed())"
765 $ fileset -r 4 "tracked() and status(0, 1, removed())"
699 $ fileset "revs('4', tracked() and status(0, 1, removed()))"
766 $ fileset "revs('4', tracked() and status(0, 1, removed()))"
700 $ fileset "revs('0', tracked() and status(0, 1, removed()))"
767 $ fileset "revs('0', tracked() and status(0, 1, removed()))"
701 a2
768 a2
702
769
703 check wdir()
770 check wdir()
704 ------------
771 ------------
705
772
706 $ hg status --removed --rev 4
773 $ hg status --removed --rev 4
707 R con.xml (no-windows !)
774 R con.xml (no-windows !)
708 $ fileset "status(4, 'wdir()', removed())"
775 $ fileset "status(4, 'wdir()', removed())"
709 con.xml (no-windows !)
776 con.xml (no-windows !)
710
777
711 $ hg status --removed --rev 2
778 $ hg status --removed --rev 2
712 R a2
779 R a2
713 $ fileset "status('2', 'wdir()', removed())"
780 $ fileset "status('2', 'wdir()', removed())"
714 a2
781 a2
715
782
716 test backward status
783 test backward status
717 --------------------
784 --------------------
718
785
719 $ hg status --removed --rev 0 --rev 4
786 $ hg status --removed --rev 0 --rev 4
720 R a2
787 R a2
721 $ hg status --added --rev 4 --rev 0
788 $ hg status --added --rev 4 --rev 0
722 A a2
789 A a2
723 $ fileset "status(4, 0, added())"
790 $ fileset "status(4, 0, added())"
724 a2
791 a2
725
792
726 test cross branch status
793 test cross branch status
727 ------------------------
794 ------------------------
728
795
729 $ hg status --added --rev 1 --rev 2
796 $ hg status --added --rev 1 --rev 2
730 A a2
797 A a2
731 $ fileset "status(1, 2, added())"
798 $ fileset "status(1, 2, added())"
732 a2
799 a2
733
800
734 test with multi revs revset
801 test with multi revs revset
735 ---------------------------
802 ---------------------------
736 $ hg status --added --rev 0:1 --rev 3:4
803 $ hg status --added --rev 0:1 --rev 3:4
737 A .hgsub
804 A .hgsub
738 A .hgsubstate
805 A .hgsubstate
739 A 1k
806 A 1k
740 A 2k
807 A 2k
741 A b2link (no-windows !)
808 A b2link (no-windows !)
742 A bin
809 A bin
743 A c1
810 A c1
744 A con.xml (no-windows !)
811 A con.xml (no-windows !)
745 $ fileset "status('0:1', '3:4', added())"
812 $ fileset "status('0:1', '3:4', added())"
746 .hgsub
813 .hgsub
747 .hgsubstate
814 .hgsubstate
748 1k
815 1k
749 2k
816 2k
750 b2link (no-windows !)
817 b2link (no-windows !)
751 bin
818 bin
752 c1
819 c1
753 con.xml (no-windows !)
820 con.xml (no-windows !)
754
821
755 tests with empty value
822 tests with empty value
756 ----------------------
823 ----------------------
757
824
758 Fully empty revset
825 Fully empty revset
759
826
760 $ fileset "status('', '4', added())"
827 $ fileset "status('', '4', added())"
761 hg: parse error: first argument to status must be a revision
828 hg: parse error: first argument to status must be a revision
762 [255]
829 [255]
763 $ fileset "status('2', '', added())"
830 $ fileset "status('2', '', added())"
764 hg: parse error: second argument to status must be a revision
831 hg: parse error: second argument to status must be a revision
765 [255]
832 [255]
766
833
767 Empty revset will error at the revset layer
834 Empty revset will error at the revset layer
768
835
769 $ fileset "status(' ', '4', added())"
836 $ fileset "status(' ', '4', added())"
770 hg: parse error at 1: not a prefix: end
837 hg: parse error at 1: not a prefix: end
771 (
838 (
772 ^ here)
839 ^ here)
773 [255]
840 [255]
774 $ fileset "status('2', ' ', added())"
841 $ fileset "status('2', ' ', added())"
775 hg: parse error at 1: not a prefix: end
842 hg: parse error at 1: not a prefix: end
776 (
843 (
777 ^ here)
844 ^ here)
778 [255]
845 [255]
General Comments 0
You need to be logged in to leave comments. Login now