##// END OF EJS Templates
ui: disable revsetaliases in plain mode (BC)...
Siddharth Agarwal -
r24883:09049042 stable
parent child Browse files
Show More
@@ -1,981 +1,984 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 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 i18n import _
8 from i18n import _
9 import errno, getpass, os, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, scmutil, util, error, formatter
10 import config, scmutil, util, error, formatter
11 from node import hex
11 from node import hex
12
12
13 samplehgrcs = {
13 samplehgrcs = {
14 'user':
14 'user':
15 """# example user config (see "hg help config" for more info)
15 """# example user config (see "hg help config" for more info)
16 [ui]
16 [ui]
17 # name and email, e.g.
17 # name and email, e.g.
18 # username = Jane Doe <jdoe@example.com>
18 # username = Jane Doe <jdoe@example.com>
19 username =
19 username =
20
20
21 [extensions]
21 [extensions]
22 # uncomment these lines to enable some popular extensions
22 # uncomment these lines to enable some popular extensions
23 # (see "hg help extensions" for more info)
23 # (see "hg help extensions" for more info)
24 #
24 #
25 # pager =
25 # pager =
26 # progress =
26 # progress =
27 # color =""",
27 # color =""",
28
28
29 'cloned':
29 'cloned':
30 """# example repository config (see "hg help config" for more info)
30 """# example repository config (see "hg help config" for more info)
31 [paths]
31 [paths]
32 default = %s
32 default = %s
33
33
34 # path aliases to other clones of this repo in URLs or filesystem paths
34 # path aliases to other clones of this repo in URLs or filesystem paths
35 # (see "hg help config.paths" for more info)
35 # (see "hg help config.paths" for more info)
36 #
36 #
37 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
37 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
38 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
38 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
39 # my-clone = /home/jdoe/jdoes-clone
39 # my-clone = /home/jdoe/jdoes-clone
40
40
41 [ui]
41 [ui]
42 # name and email (local to this repository, optional), e.g.
42 # name and email (local to this repository, optional), e.g.
43 # username = Jane Doe <jdoe@example.com>
43 # username = Jane Doe <jdoe@example.com>
44 """,
44 """,
45
45
46 'local':
46 'local':
47 """# example repository config (see "hg help config" for more info)
47 """# example repository config (see "hg help config" for more info)
48 [paths]
48 [paths]
49 # path aliases to other clones of this repo in URLs or filesystem paths
49 # path aliases to other clones of this repo in URLs or filesystem paths
50 # (see "hg help config.paths" for more info)
50 # (see "hg help config.paths" for more info)
51 #
51 #
52 # default = http://example.com/hg/example-repo
52 # default = http://example.com/hg/example-repo
53 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
53 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
54 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
54 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
55 # my-clone = /home/jdoe/jdoes-clone
55 # my-clone = /home/jdoe/jdoes-clone
56
56
57 [ui]
57 [ui]
58 # name and email (local to this repository, optional), e.g.
58 # name and email (local to this repository, optional), e.g.
59 # username = Jane Doe <jdoe@example.com>
59 # username = Jane Doe <jdoe@example.com>
60 """,
60 """,
61
61
62 'global':
62 'global':
63 """# example system-wide hg config (see "hg help config" for more info)
63 """# example system-wide hg config (see "hg help config" for more info)
64
64
65 [extensions]
65 [extensions]
66 # uncomment these lines to enable some popular extensions
66 # uncomment these lines to enable some popular extensions
67 # (see "hg help extensions" for more info)
67 # (see "hg help extensions" for more info)
68 #
68 #
69 # blackbox =
69 # blackbox =
70 # progress =
70 # progress =
71 # color =
71 # color =
72 # pager =""",
72 # pager =""",
73 }
73 }
74
74
75 class ui(object):
75 class ui(object):
76 def __init__(self, src=None):
76 def __init__(self, src=None):
77 # _buffers: used for temporary capture of output
77 # _buffers: used for temporary capture of output
78 self._buffers = []
78 self._buffers = []
79 # _bufferstates:
79 # _bufferstates:
80 # should the temporary capture include stderr and subprocess output
80 # should the temporary capture include stderr and subprocess output
81 self._bufferstates = []
81 self._bufferstates = []
82 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
82 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
83 self._reportuntrusted = True
83 self._reportuntrusted = True
84 self._ocfg = config.config() # overlay
84 self._ocfg = config.config() # overlay
85 self._tcfg = config.config() # trusted
85 self._tcfg = config.config() # trusted
86 self._ucfg = config.config() # untrusted
86 self._ucfg = config.config() # untrusted
87 self._trustusers = set()
87 self._trustusers = set()
88 self._trustgroups = set()
88 self._trustgroups = set()
89 self.callhooks = True
89 self.callhooks = True
90
90
91 if src:
91 if src:
92 self.fout = src.fout
92 self.fout = src.fout
93 self.ferr = src.ferr
93 self.ferr = src.ferr
94 self.fin = src.fin
94 self.fin = src.fin
95
95
96 self._tcfg = src._tcfg.copy()
96 self._tcfg = src._tcfg.copy()
97 self._ucfg = src._ucfg.copy()
97 self._ucfg = src._ucfg.copy()
98 self._ocfg = src._ocfg.copy()
98 self._ocfg = src._ocfg.copy()
99 self._trustusers = src._trustusers.copy()
99 self._trustusers = src._trustusers.copy()
100 self._trustgroups = src._trustgroups.copy()
100 self._trustgroups = src._trustgroups.copy()
101 self.environ = src.environ
101 self.environ = src.environ
102 self.callhooks = src.callhooks
102 self.callhooks = src.callhooks
103 self.fixconfig()
103 self.fixconfig()
104 else:
104 else:
105 self.fout = sys.stdout
105 self.fout = sys.stdout
106 self.ferr = sys.stderr
106 self.ferr = sys.stderr
107 self.fin = sys.stdin
107 self.fin = sys.stdin
108
108
109 # shared read-only environment
109 # shared read-only environment
110 self.environ = os.environ
110 self.environ = os.environ
111 # we always trust global config files
111 # we always trust global config files
112 for f in scmutil.rcpath():
112 for f in scmutil.rcpath():
113 self.readconfig(f, trust=True)
113 self.readconfig(f, trust=True)
114
114
115 def copy(self):
115 def copy(self):
116 return self.__class__(self)
116 return self.__class__(self)
117
117
118 def formatter(self, topic, opts):
118 def formatter(self, topic, opts):
119 return formatter.formatter(self, topic, opts)
119 return formatter.formatter(self, topic, opts)
120
120
121 def _trusted(self, fp, f):
121 def _trusted(self, fp, f):
122 st = util.fstat(fp)
122 st = util.fstat(fp)
123 if util.isowner(st):
123 if util.isowner(st):
124 return True
124 return True
125
125
126 tusers, tgroups = self._trustusers, self._trustgroups
126 tusers, tgroups = self._trustusers, self._trustgroups
127 if '*' in tusers or '*' in tgroups:
127 if '*' in tusers or '*' in tgroups:
128 return True
128 return True
129
129
130 user = util.username(st.st_uid)
130 user = util.username(st.st_uid)
131 group = util.groupname(st.st_gid)
131 group = util.groupname(st.st_gid)
132 if user in tusers or group in tgroups or user == util.username():
132 if user in tusers or group in tgroups or user == util.username():
133 return True
133 return True
134
134
135 if self._reportuntrusted:
135 if self._reportuntrusted:
136 self.warn(_('not trusting file %s from untrusted '
136 self.warn(_('not trusting file %s from untrusted '
137 'user %s, group %s\n') % (f, user, group))
137 'user %s, group %s\n') % (f, user, group))
138 return False
138 return False
139
139
140 def readconfig(self, filename, root=None, trust=False,
140 def readconfig(self, filename, root=None, trust=False,
141 sections=None, remap=None):
141 sections=None, remap=None):
142 try:
142 try:
143 fp = open(filename)
143 fp = open(filename)
144 except IOError:
144 except IOError:
145 if not sections: # ignore unless we were looking for something
145 if not sections: # ignore unless we were looking for something
146 return
146 return
147 raise
147 raise
148
148
149 cfg = config.config()
149 cfg = config.config()
150 trusted = sections or trust or self._trusted(fp, filename)
150 trusted = sections or trust or self._trusted(fp, filename)
151
151
152 try:
152 try:
153 cfg.read(filename, fp, sections=sections, remap=remap)
153 cfg.read(filename, fp, sections=sections, remap=remap)
154 fp.close()
154 fp.close()
155 except error.ConfigError, inst:
155 except error.ConfigError, inst:
156 if trusted:
156 if trusted:
157 raise
157 raise
158 self.warn(_("ignored: %s\n") % str(inst))
158 self.warn(_("ignored: %s\n") % str(inst))
159
159
160 if self.plain():
160 if self.plain():
161 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
161 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
162 'logtemplate', 'statuscopies', 'style',
162 'logtemplate', 'statuscopies', 'style',
163 'traceback', 'verbose'):
163 'traceback', 'verbose'):
164 if k in cfg['ui']:
164 if k in cfg['ui']:
165 del cfg['ui'][k]
165 del cfg['ui'][k]
166 for k, v in cfg.items('defaults'):
166 for k, v in cfg.items('defaults'):
167 del cfg['defaults'][k]
167 del cfg['defaults'][k]
168 # Don't remove aliases from the configuration if in the exceptionlist
168 # Don't remove aliases from the configuration if in the exceptionlist
169 if self.plain('alias'):
169 if self.plain('alias'):
170 for k, v in cfg.items('alias'):
170 for k, v in cfg.items('alias'):
171 del cfg['alias'][k]
171 del cfg['alias'][k]
172 if self.plain('revsetalias'):
173 for k, v in cfg.items('revsetalias'):
174 del cfg['revsetalias'][k]
172
175
173 if trusted:
176 if trusted:
174 self._tcfg.update(cfg)
177 self._tcfg.update(cfg)
175 self._tcfg.update(self._ocfg)
178 self._tcfg.update(self._ocfg)
176 self._ucfg.update(cfg)
179 self._ucfg.update(cfg)
177 self._ucfg.update(self._ocfg)
180 self._ucfg.update(self._ocfg)
178
181
179 if root is None:
182 if root is None:
180 root = os.path.expanduser('~')
183 root = os.path.expanduser('~')
181 self.fixconfig(root=root)
184 self.fixconfig(root=root)
182
185
183 def fixconfig(self, root=None, section=None):
186 def fixconfig(self, root=None, section=None):
184 if section in (None, 'paths'):
187 if section in (None, 'paths'):
185 # expand vars and ~
188 # expand vars and ~
186 # translate paths relative to root (or home) into absolute paths
189 # translate paths relative to root (or home) into absolute paths
187 root = root or os.getcwd()
190 root = root or os.getcwd()
188 for c in self._tcfg, self._ucfg, self._ocfg:
191 for c in self._tcfg, self._ucfg, self._ocfg:
189 for n, p in c.items('paths'):
192 for n, p in c.items('paths'):
190 if not p:
193 if not p:
191 continue
194 continue
192 if '%%' in p:
195 if '%%' in p:
193 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
196 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
194 % (n, p, self.configsource('paths', n)))
197 % (n, p, self.configsource('paths', n)))
195 p = p.replace('%%', '%')
198 p = p.replace('%%', '%')
196 p = util.expandpath(p)
199 p = util.expandpath(p)
197 if not util.hasscheme(p) and not os.path.isabs(p):
200 if not util.hasscheme(p) and not os.path.isabs(p):
198 p = os.path.normpath(os.path.join(root, p))
201 p = os.path.normpath(os.path.join(root, p))
199 c.set("paths", n, p)
202 c.set("paths", n, p)
200
203
201 if section in (None, 'ui'):
204 if section in (None, 'ui'):
202 # update ui options
205 # update ui options
203 self.debugflag = self.configbool('ui', 'debug')
206 self.debugflag = self.configbool('ui', 'debug')
204 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
207 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
205 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
208 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
206 if self.verbose and self.quiet:
209 if self.verbose and self.quiet:
207 self.quiet = self.verbose = False
210 self.quiet = self.verbose = False
208 self._reportuntrusted = self.debugflag or self.configbool("ui",
211 self._reportuntrusted = self.debugflag or self.configbool("ui",
209 "report_untrusted", True)
212 "report_untrusted", True)
210 self.tracebackflag = self.configbool('ui', 'traceback', False)
213 self.tracebackflag = self.configbool('ui', 'traceback', False)
211
214
212 if section in (None, 'trusted'):
215 if section in (None, 'trusted'):
213 # update trust information
216 # update trust information
214 self._trustusers.update(self.configlist('trusted', 'users'))
217 self._trustusers.update(self.configlist('trusted', 'users'))
215 self._trustgroups.update(self.configlist('trusted', 'groups'))
218 self._trustgroups.update(self.configlist('trusted', 'groups'))
216
219
217 def backupconfig(self, section, item):
220 def backupconfig(self, section, item):
218 return (self._ocfg.backup(section, item),
221 return (self._ocfg.backup(section, item),
219 self._tcfg.backup(section, item),
222 self._tcfg.backup(section, item),
220 self._ucfg.backup(section, item),)
223 self._ucfg.backup(section, item),)
221 def restoreconfig(self, data):
224 def restoreconfig(self, data):
222 self._ocfg.restore(data[0])
225 self._ocfg.restore(data[0])
223 self._tcfg.restore(data[1])
226 self._tcfg.restore(data[1])
224 self._ucfg.restore(data[2])
227 self._ucfg.restore(data[2])
225
228
226 def setconfig(self, section, name, value, source=''):
229 def setconfig(self, section, name, value, source=''):
227 for cfg in (self._ocfg, self._tcfg, self._ucfg):
230 for cfg in (self._ocfg, self._tcfg, self._ucfg):
228 cfg.set(section, name, value, source)
231 cfg.set(section, name, value, source)
229 self.fixconfig(section=section)
232 self.fixconfig(section=section)
230
233
231 def _data(self, untrusted):
234 def _data(self, untrusted):
232 return untrusted and self._ucfg or self._tcfg
235 return untrusted and self._ucfg or self._tcfg
233
236
234 def configsource(self, section, name, untrusted=False):
237 def configsource(self, section, name, untrusted=False):
235 return self._data(untrusted).source(section, name) or 'none'
238 return self._data(untrusted).source(section, name) or 'none'
236
239
237 def config(self, section, name, default=None, untrusted=False):
240 def config(self, section, name, default=None, untrusted=False):
238 if isinstance(name, list):
241 if isinstance(name, list):
239 alternates = name
242 alternates = name
240 else:
243 else:
241 alternates = [name]
244 alternates = [name]
242
245
243 for n in alternates:
246 for n in alternates:
244 value = self._data(untrusted).get(section, n, None)
247 value = self._data(untrusted).get(section, n, None)
245 if value is not None:
248 if value is not None:
246 name = n
249 name = n
247 break
250 break
248 else:
251 else:
249 value = default
252 value = default
250
253
251 if self.debugflag and not untrusted and self._reportuntrusted:
254 if self.debugflag and not untrusted and self._reportuntrusted:
252 for n in alternates:
255 for n in alternates:
253 uvalue = self._ucfg.get(section, n)
256 uvalue = self._ucfg.get(section, n)
254 if uvalue is not None and uvalue != value:
257 if uvalue is not None and uvalue != value:
255 self.debug("ignoring untrusted configuration option "
258 self.debug("ignoring untrusted configuration option "
256 "%s.%s = %s\n" % (section, n, uvalue))
259 "%s.%s = %s\n" % (section, n, uvalue))
257 return value
260 return value
258
261
259 def configpath(self, section, name, default=None, untrusted=False):
262 def configpath(self, section, name, default=None, untrusted=False):
260 'get a path config item, expanded relative to repo root or config file'
263 'get a path config item, expanded relative to repo root or config file'
261 v = self.config(section, name, default, untrusted)
264 v = self.config(section, name, default, untrusted)
262 if v is None:
265 if v is None:
263 return None
266 return None
264 if not os.path.isabs(v) or "://" not in v:
267 if not os.path.isabs(v) or "://" not in v:
265 src = self.configsource(section, name, untrusted)
268 src = self.configsource(section, name, untrusted)
266 if ':' in src:
269 if ':' in src:
267 base = os.path.dirname(src.rsplit(':')[0])
270 base = os.path.dirname(src.rsplit(':')[0])
268 v = os.path.join(base, os.path.expanduser(v))
271 v = os.path.join(base, os.path.expanduser(v))
269 return v
272 return v
270
273
271 def configbool(self, section, name, default=False, untrusted=False):
274 def configbool(self, section, name, default=False, untrusted=False):
272 """parse a configuration element as a boolean
275 """parse a configuration element as a boolean
273
276
274 >>> u = ui(); s = 'foo'
277 >>> u = ui(); s = 'foo'
275 >>> u.setconfig(s, 'true', 'yes')
278 >>> u.setconfig(s, 'true', 'yes')
276 >>> u.configbool(s, 'true')
279 >>> u.configbool(s, 'true')
277 True
280 True
278 >>> u.setconfig(s, 'false', 'no')
281 >>> u.setconfig(s, 'false', 'no')
279 >>> u.configbool(s, 'false')
282 >>> u.configbool(s, 'false')
280 False
283 False
281 >>> u.configbool(s, 'unknown')
284 >>> u.configbool(s, 'unknown')
282 False
285 False
283 >>> u.configbool(s, 'unknown', True)
286 >>> u.configbool(s, 'unknown', True)
284 True
287 True
285 >>> u.setconfig(s, 'invalid', 'somevalue')
288 >>> u.setconfig(s, 'invalid', 'somevalue')
286 >>> u.configbool(s, 'invalid')
289 >>> u.configbool(s, 'invalid')
287 Traceback (most recent call last):
290 Traceback (most recent call last):
288 ...
291 ...
289 ConfigError: foo.invalid is not a boolean ('somevalue')
292 ConfigError: foo.invalid is not a boolean ('somevalue')
290 """
293 """
291
294
292 v = self.config(section, name, None, untrusted)
295 v = self.config(section, name, None, untrusted)
293 if v is None:
296 if v is None:
294 return default
297 return default
295 if isinstance(v, bool):
298 if isinstance(v, bool):
296 return v
299 return v
297 b = util.parsebool(v)
300 b = util.parsebool(v)
298 if b is None:
301 if b is None:
299 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
302 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
300 % (section, name, v))
303 % (section, name, v))
301 return b
304 return b
302
305
303 def configint(self, section, name, default=None, untrusted=False):
306 def configint(self, section, name, default=None, untrusted=False):
304 """parse a configuration element as an integer
307 """parse a configuration element as an integer
305
308
306 >>> u = ui(); s = 'foo'
309 >>> u = ui(); s = 'foo'
307 >>> u.setconfig(s, 'int1', '42')
310 >>> u.setconfig(s, 'int1', '42')
308 >>> u.configint(s, 'int1')
311 >>> u.configint(s, 'int1')
309 42
312 42
310 >>> u.setconfig(s, 'int2', '-42')
313 >>> u.setconfig(s, 'int2', '-42')
311 >>> u.configint(s, 'int2')
314 >>> u.configint(s, 'int2')
312 -42
315 -42
313 >>> u.configint(s, 'unknown', 7)
316 >>> u.configint(s, 'unknown', 7)
314 7
317 7
315 >>> u.setconfig(s, 'invalid', 'somevalue')
318 >>> u.setconfig(s, 'invalid', 'somevalue')
316 >>> u.configint(s, 'invalid')
319 >>> u.configint(s, 'invalid')
317 Traceback (most recent call last):
320 Traceback (most recent call last):
318 ...
321 ...
319 ConfigError: foo.invalid is not an integer ('somevalue')
322 ConfigError: foo.invalid is not an integer ('somevalue')
320 """
323 """
321
324
322 v = self.config(section, name, None, untrusted)
325 v = self.config(section, name, None, untrusted)
323 if v is None:
326 if v is None:
324 return default
327 return default
325 try:
328 try:
326 return int(v)
329 return int(v)
327 except ValueError:
330 except ValueError:
328 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
331 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
329 % (section, name, v))
332 % (section, name, v))
330
333
331 def configbytes(self, section, name, default=0, untrusted=False):
334 def configbytes(self, section, name, default=0, untrusted=False):
332 """parse a configuration element as a quantity in bytes
335 """parse a configuration element as a quantity in bytes
333
336
334 Units can be specified as b (bytes), k or kb (kilobytes), m or
337 Units can be specified as b (bytes), k or kb (kilobytes), m or
335 mb (megabytes), g or gb (gigabytes).
338 mb (megabytes), g or gb (gigabytes).
336
339
337 >>> u = ui(); s = 'foo'
340 >>> u = ui(); s = 'foo'
338 >>> u.setconfig(s, 'val1', '42')
341 >>> u.setconfig(s, 'val1', '42')
339 >>> u.configbytes(s, 'val1')
342 >>> u.configbytes(s, 'val1')
340 42
343 42
341 >>> u.setconfig(s, 'val2', '42.5 kb')
344 >>> u.setconfig(s, 'val2', '42.5 kb')
342 >>> u.configbytes(s, 'val2')
345 >>> u.configbytes(s, 'val2')
343 43520
346 43520
344 >>> u.configbytes(s, 'unknown', '7 MB')
347 >>> u.configbytes(s, 'unknown', '7 MB')
345 7340032
348 7340032
346 >>> u.setconfig(s, 'invalid', 'somevalue')
349 >>> u.setconfig(s, 'invalid', 'somevalue')
347 >>> u.configbytes(s, 'invalid')
350 >>> u.configbytes(s, 'invalid')
348 Traceback (most recent call last):
351 Traceback (most recent call last):
349 ...
352 ...
350 ConfigError: foo.invalid is not a byte quantity ('somevalue')
353 ConfigError: foo.invalid is not a byte quantity ('somevalue')
351 """
354 """
352
355
353 value = self.config(section, name)
356 value = self.config(section, name)
354 if value is None:
357 if value is None:
355 if not isinstance(default, str):
358 if not isinstance(default, str):
356 return default
359 return default
357 value = default
360 value = default
358 try:
361 try:
359 return util.sizetoint(value)
362 return util.sizetoint(value)
360 except error.ParseError:
363 except error.ParseError:
361 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
364 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
362 % (section, name, value))
365 % (section, name, value))
363
366
364 def configlist(self, section, name, default=None, untrusted=False):
367 def configlist(self, section, name, default=None, untrusted=False):
365 """parse a configuration element as a list of comma/space separated
368 """parse a configuration element as a list of comma/space separated
366 strings
369 strings
367
370
368 >>> u = ui(); s = 'foo'
371 >>> u = ui(); s = 'foo'
369 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
372 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
370 >>> u.configlist(s, 'list1')
373 >>> u.configlist(s, 'list1')
371 ['this', 'is', 'a small', 'test']
374 ['this', 'is', 'a small', 'test']
372 """
375 """
373
376
374 def _parse_plain(parts, s, offset):
377 def _parse_plain(parts, s, offset):
375 whitespace = False
378 whitespace = False
376 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
379 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
377 whitespace = True
380 whitespace = True
378 offset += 1
381 offset += 1
379 if offset >= len(s):
382 if offset >= len(s):
380 return None, parts, offset
383 return None, parts, offset
381 if whitespace:
384 if whitespace:
382 parts.append('')
385 parts.append('')
383 if s[offset] == '"' and not parts[-1]:
386 if s[offset] == '"' and not parts[-1]:
384 return _parse_quote, parts, offset + 1
387 return _parse_quote, parts, offset + 1
385 elif s[offset] == '"' and parts[-1][-1] == '\\':
388 elif s[offset] == '"' and parts[-1][-1] == '\\':
386 parts[-1] = parts[-1][:-1] + s[offset]
389 parts[-1] = parts[-1][:-1] + s[offset]
387 return _parse_plain, parts, offset + 1
390 return _parse_plain, parts, offset + 1
388 parts[-1] += s[offset]
391 parts[-1] += s[offset]
389 return _parse_plain, parts, offset + 1
392 return _parse_plain, parts, offset + 1
390
393
391 def _parse_quote(parts, s, offset):
394 def _parse_quote(parts, s, offset):
392 if offset < len(s) and s[offset] == '"': # ""
395 if offset < len(s) and s[offset] == '"': # ""
393 parts.append('')
396 parts.append('')
394 offset += 1
397 offset += 1
395 while offset < len(s) and (s[offset].isspace() or
398 while offset < len(s) and (s[offset].isspace() or
396 s[offset] == ','):
399 s[offset] == ','):
397 offset += 1
400 offset += 1
398 return _parse_plain, parts, offset
401 return _parse_plain, parts, offset
399
402
400 while offset < len(s) and s[offset] != '"':
403 while offset < len(s) and s[offset] != '"':
401 if (s[offset] == '\\' and offset + 1 < len(s)
404 if (s[offset] == '\\' and offset + 1 < len(s)
402 and s[offset + 1] == '"'):
405 and s[offset + 1] == '"'):
403 offset += 1
406 offset += 1
404 parts[-1] += '"'
407 parts[-1] += '"'
405 else:
408 else:
406 parts[-1] += s[offset]
409 parts[-1] += s[offset]
407 offset += 1
410 offset += 1
408
411
409 if offset >= len(s):
412 if offset >= len(s):
410 real_parts = _configlist(parts[-1])
413 real_parts = _configlist(parts[-1])
411 if not real_parts:
414 if not real_parts:
412 parts[-1] = '"'
415 parts[-1] = '"'
413 else:
416 else:
414 real_parts[0] = '"' + real_parts[0]
417 real_parts[0] = '"' + real_parts[0]
415 parts = parts[:-1]
418 parts = parts[:-1]
416 parts.extend(real_parts)
419 parts.extend(real_parts)
417 return None, parts, offset
420 return None, parts, offset
418
421
419 offset += 1
422 offset += 1
420 while offset < len(s) and s[offset] in [' ', ',']:
423 while offset < len(s) and s[offset] in [' ', ',']:
421 offset += 1
424 offset += 1
422
425
423 if offset < len(s):
426 if offset < len(s):
424 if offset + 1 == len(s) and s[offset] == '"':
427 if offset + 1 == len(s) and s[offset] == '"':
425 parts[-1] += '"'
428 parts[-1] += '"'
426 offset += 1
429 offset += 1
427 else:
430 else:
428 parts.append('')
431 parts.append('')
429 else:
432 else:
430 return None, parts, offset
433 return None, parts, offset
431
434
432 return _parse_plain, parts, offset
435 return _parse_plain, parts, offset
433
436
434 def _configlist(s):
437 def _configlist(s):
435 s = s.rstrip(' ,')
438 s = s.rstrip(' ,')
436 if not s:
439 if not s:
437 return []
440 return []
438 parser, parts, offset = _parse_plain, [''], 0
441 parser, parts, offset = _parse_plain, [''], 0
439 while parser:
442 while parser:
440 parser, parts, offset = parser(parts, s, offset)
443 parser, parts, offset = parser(parts, s, offset)
441 return parts
444 return parts
442
445
443 result = self.config(section, name, untrusted=untrusted)
446 result = self.config(section, name, untrusted=untrusted)
444 if result is None:
447 if result is None:
445 result = default or []
448 result = default or []
446 if isinstance(result, basestring):
449 if isinstance(result, basestring):
447 result = _configlist(result.lstrip(' ,\n'))
450 result = _configlist(result.lstrip(' ,\n'))
448 if result is None:
451 if result is None:
449 result = default or []
452 result = default or []
450 return result
453 return result
451
454
452 def has_section(self, section, untrusted=False):
455 def has_section(self, section, untrusted=False):
453 '''tell whether section exists in config.'''
456 '''tell whether section exists in config.'''
454 return section in self._data(untrusted)
457 return section in self._data(untrusted)
455
458
456 def configitems(self, section, untrusted=False):
459 def configitems(self, section, untrusted=False):
457 items = self._data(untrusted).items(section)
460 items = self._data(untrusted).items(section)
458 if self.debugflag and not untrusted and self._reportuntrusted:
461 if self.debugflag and not untrusted and self._reportuntrusted:
459 for k, v in self._ucfg.items(section):
462 for k, v in self._ucfg.items(section):
460 if self._tcfg.get(section, k) != v:
463 if self._tcfg.get(section, k) != v:
461 self.debug("ignoring untrusted configuration option "
464 self.debug("ignoring untrusted configuration option "
462 "%s.%s = %s\n" % (section, k, v))
465 "%s.%s = %s\n" % (section, k, v))
463 return items
466 return items
464
467
465 def walkconfig(self, untrusted=False):
468 def walkconfig(self, untrusted=False):
466 cfg = self._data(untrusted)
469 cfg = self._data(untrusted)
467 for section in cfg.sections():
470 for section in cfg.sections():
468 for name, value in self.configitems(section, untrusted):
471 for name, value in self.configitems(section, untrusted):
469 yield section, name, value
472 yield section, name, value
470
473
471 def plain(self, feature=None):
474 def plain(self, feature=None):
472 '''is plain mode active?
475 '''is plain mode active?
473
476
474 Plain mode means that all configuration variables which affect
477 Plain mode means that all configuration variables which affect
475 the behavior and output of Mercurial should be
478 the behavior and output of Mercurial should be
476 ignored. Additionally, the output should be stable,
479 ignored. Additionally, the output should be stable,
477 reproducible and suitable for use in scripts or applications.
480 reproducible and suitable for use in scripts or applications.
478
481
479 The only way to trigger plain mode is by setting either the
482 The only way to trigger plain mode is by setting either the
480 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
483 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
481
484
482 The return value can either be
485 The return value can either be
483 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
486 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
484 - True otherwise
487 - True otherwise
485 '''
488 '''
486 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
489 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
487 return False
490 return False
488 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
491 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
489 if feature and exceptions:
492 if feature and exceptions:
490 return feature not in exceptions
493 return feature not in exceptions
491 return True
494 return True
492
495
493 def username(self):
496 def username(self):
494 """Return default username to be used in commits.
497 """Return default username to be used in commits.
495
498
496 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
499 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
497 and stop searching if one of these is set.
500 and stop searching if one of these is set.
498 If not found and ui.askusername is True, ask the user, else use
501 If not found and ui.askusername is True, ask the user, else use
499 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
502 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
500 """
503 """
501 user = os.environ.get("HGUSER")
504 user = os.environ.get("HGUSER")
502 if user is None:
505 if user is None:
503 user = self.config("ui", ["username", "user"])
506 user = self.config("ui", ["username", "user"])
504 if user is not None:
507 if user is not None:
505 user = os.path.expandvars(user)
508 user = os.path.expandvars(user)
506 if user is None:
509 if user is None:
507 user = os.environ.get("EMAIL")
510 user = os.environ.get("EMAIL")
508 if user is None and self.configbool("ui", "askusername"):
511 if user is None and self.configbool("ui", "askusername"):
509 user = self.prompt(_("enter a commit username:"), default=None)
512 user = self.prompt(_("enter a commit username:"), default=None)
510 if user is None and not self.interactive():
513 if user is None and not self.interactive():
511 try:
514 try:
512 user = '%s@%s' % (util.getuser(), socket.getfqdn())
515 user = '%s@%s' % (util.getuser(), socket.getfqdn())
513 self.warn(_("no username found, using '%s' instead\n") % user)
516 self.warn(_("no username found, using '%s' instead\n") % user)
514 except KeyError:
517 except KeyError:
515 pass
518 pass
516 if not user:
519 if not user:
517 raise util.Abort(_('no username supplied'),
520 raise util.Abort(_('no username supplied'),
518 hint=_('use "hg config --edit" '
521 hint=_('use "hg config --edit" '
519 'to set your username'))
522 'to set your username'))
520 if "\n" in user:
523 if "\n" in user:
521 raise util.Abort(_("username %s contains a newline\n") % repr(user))
524 raise util.Abort(_("username %s contains a newline\n") % repr(user))
522 return user
525 return user
523
526
524 def shortuser(self, user):
527 def shortuser(self, user):
525 """Return a short representation of a user name or email address."""
528 """Return a short representation of a user name or email address."""
526 if not self.verbose:
529 if not self.verbose:
527 user = util.shortuser(user)
530 user = util.shortuser(user)
528 return user
531 return user
529
532
530 def expandpath(self, loc, default=None):
533 def expandpath(self, loc, default=None):
531 """Return repository location relative to cwd or from [paths]"""
534 """Return repository location relative to cwd or from [paths]"""
532 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
535 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
533 return loc
536 return loc
534
537
535 p = self.paths.getpath(loc, default=default)
538 p = self.paths.getpath(loc, default=default)
536 if p:
539 if p:
537 return p.loc
540 return p.loc
538 return loc
541 return loc
539
542
540 @util.propertycache
543 @util.propertycache
541 def paths(self):
544 def paths(self):
542 return paths(self)
545 return paths(self)
543
546
544 def pushbuffer(self, error=False, subproc=False):
547 def pushbuffer(self, error=False, subproc=False):
545 """install a buffer to capture standard output of the ui object
548 """install a buffer to capture standard output of the ui object
546
549
547 If error is True, the error output will be captured too.
550 If error is True, the error output will be captured too.
548
551
549 If subproc is True, output from subprocesses (typically hooks) will be
552 If subproc is True, output from subprocesses (typically hooks) will be
550 captured too."""
553 captured too."""
551 self._buffers.append([])
554 self._buffers.append([])
552 self._bufferstates.append((error, subproc))
555 self._bufferstates.append((error, subproc))
553
556
554 def popbuffer(self, labeled=False):
557 def popbuffer(self, labeled=False):
555 '''pop the last buffer and return the buffered output
558 '''pop the last buffer and return the buffered output
556
559
557 If labeled is True, any labels associated with buffered
560 If labeled is True, any labels associated with buffered
558 output will be handled. By default, this has no effect
561 output will be handled. By default, this has no effect
559 on the output returned, but extensions and GUI tools may
562 on the output returned, but extensions and GUI tools may
560 handle this argument and returned styled output. If output
563 handle this argument and returned styled output. If output
561 is being buffered so it can be captured and parsed or
564 is being buffered so it can be captured and parsed or
562 processed, labeled should not be set to True.
565 processed, labeled should not be set to True.
563 '''
566 '''
564 self._bufferstates.pop()
567 self._bufferstates.pop()
565 return "".join(self._buffers.pop())
568 return "".join(self._buffers.pop())
566
569
567 def write(self, *args, **opts):
570 def write(self, *args, **opts):
568 '''write args to output
571 '''write args to output
569
572
570 By default, this method simply writes to the buffer or stdout,
573 By default, this method simply writes to the buffer or stdout,
571 but extensions or GUI tools may override this method,
574 but extensions or GUI tools may override this method,
572 write_err(), popbuffer(), and label() to style output from
575 write_err(), popbuffer(), and label() to style output from
573 various parts of hg.
576 various parts of hg.
574
577
575 An optional keyword argument, "label", can be passed in.
578 An optional keyword argument, "label", can be passed in.
576 This should be a string containing label names separated by
579 This should be a string containing label names separated by
577 space. Label names take the form of "topic.type". For example,
580 space. Label names take the form of "topic.type". For example,
578 ui.debug() issues a label of "ui.debug".
581 ui.debug() issues a label of "ui.debug".
579
582
580 When labeling output for a specific command, a label of
583 When labeling output for a specific command, a label of
581 "cmdname.type" is recommended. For example, status issues
584 "cmdname.type" is recommended. For example, status issues
582 a label of "status.modified" for modified files.
585 a label of "status.modified" for modified files.
583 '''
586 '''
584 if self._buffers:
587 if self._buffers:
585 self._buffers[-1].extend([str(a) for a in args])
588 self._buffers[-1].extend([str(a) for a in args])
586 else:
589 else:
587 for a in args:
590 for a in args:
588 self.fout.write(str(a))
591 self.fout.write(str(a))
589
592
590 def write_err(self, *args, **opts):
593 def write_err(self, *args, **opts):
591 try:
594 try:
592 if self._bufferstates and self._bufferstates[-1][0]:
595 if self._bufferstates and self._bufferstates[-1][0]:
593 return self.write(*args, **opts)
596 return self.write(*args, **opts)
594 if not getattr(self.fout, 'closed', False):
597 if not getattr(self.fout, 'closed', False):
595 self.fout.flush()
598 self.fout.flush()
596 for a in args:
599 for a in args:
597 self.ferr.write(str(a))
600 self.ferr.write(str(a))
598 # stderr may be buffered under win32 when redirected to files,
601 # stderr may be buffered under win32 when redirected to files,
599 # including stdout.
602 # including stdout.
600 if not getattr(self.ferr, 'closed', False):
603 if not getattr(self.ferr, 'closed', False):
601 self.ferr.flush()
604 self.ferr.flush()
602 except IOError, inst:
605 except IOError, inst:
603 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
606 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
604 raise
607 raise
605
608
606 def flush(self):
609 def flush(self):
607 try: self.fout.flush()
610 try: self.fout.flush()
608 except (IOError, ValueError): pass
611 except (IOError, ValueError): pass
609 try: self.ferr.flush()
612 try: self.ferr.flush()
610 except (IOError, ValueError): pass
613 except (IOError, ValueError): pass
611
614
612 def _isatty(self, fh):
615 def _isatty(self, fh):
613 if self.configbool('ui', 'nontty', False):
616 if self.configbool('ui', 'nontty', False):
614 return False
617 return False
615 return util.isatty(fh)
618 return util.isatty(fh)
616
619
617 def interactive(self):
620 def interactive(self):
618 '''is interactive input allowed?
621 '''is interactive input allowed?
619
622
620 An interactive session is a session where input can be reasonably read
623 An interactive session is a session where input can be reasonably read
621 from `sys.stdin'. If this function returns false, any attempt to read
624 from `sys.stdin'. If this function returns false, any attempt to read
622 from stdin should fail with an error, unless a sensible default has been
625 from stdin should fail with an error, unless a sensible default has been
623 specified.
626 specified.
624
627
625 Interactiveness is triggered by the value of the `ui.interactive'
628 Interactiveness is triggered by the value of the `ui.interactive'
626 configuration variable or - if it is unset - when `sys.stdin' points
629 configuration variable or - if it is unset - when `sys.stdin' points
627 to a terminal device.
630 to a terminal device.
628
631
629 This function refers to input only; for output, see `ui.formatted()'.
632 This function refers to input only; for output, see `ui.formatted()'.
630 '''
633 '''
631 i = self.configbool("ui", "interactive", None)
634 i = self.configbool("ui", "interactive", None)
632 if i is None:
635 if i is None:
633 # some environments replace stdin without implementing isatty
636 # some environments replace stdin without implementing isatty
634 # usually those are non-interactive
637 # usually those are non-interactive
635 return self._isatty(self.fin)
638 return self._isatty(self.fin)
636
639
637 return i
640 return i
638
641
639 def termwidth(self):
642 def termwidth(self):
640 '''how wide is the terminal in columns?
643 '''how wide is the terminal in columns?
641 '''
644 '''
642 if 'COLUMNS' in os.environ:
645 if 'COLUMNS' in os.environ:
643 try:
646 try:
644 return int(os.environ['COLUMNS'])
647 return int(os.environ['COLUMNS'])
645 except ValueError:
648 except ValueError:
646 pass
649 pass
647 return util.termwidth()
650 return util.termwidth()
648
651
649 def formatted(self):
652 def formatted(self):
650 '''should formatted output be used?
653 '''should formatted output be used?
651
654
652 It is often desirable to format the output to suite the output medium.
655 It is often desirable to format the output to suite the output medium.
653 Examples of this are truncating long lines or colorizing messages.
656 Examples of this are truncating long lines or colorizing messages.
654 However, this is not often not desirable when piping output into other
657 However, this is not often not desirable when piping output into other
655 utilities, e.g. `grep'.
658 utilities, e.g. `grep'.
656
659
657 Formatted output is triggered by the value of the `ui.formatted'
660 Formatted output is triggered by the value of the `ui.formatted'
658 configuration variable or - if it is unset - when `sys.stdout' points
661 configuration variable or - if it is unset - when `sys.stdout' points
659 to a terminal device. Please note that `ui.formatted' should be
662 to a terminal device. Please note that `ui.formatted' should be
660 considered an implementation detail; it is not intended for use outside
663 considered an implementation detail; it is not intended for use outside
661 Mercurial or its extensions.
664 Mercurial or its extensions.
662
665
663 This function refers to output only; for input, see `ui.interactive()'.
666 This function refers to output only; for input, see `ui.interactive()'.
664 This function always returns false when in plain mode, see `ui.plain()'.
667 This function always returns false when in plain mode, see `ui.plain()'.
665 '''
668 '''
666 if self.plain():
669 if self.plain():
667 return False
670 return False
668
671
669 i = self.configbool("ui", "formatted", None)
672 i = self.configbool("ui", "formatted", None)
670 if i is None:
673 if i is None:
671 # some environments replace stdout without implementing isatty
674 # some environments replace stdout without implementing isatty
672 # usually those are non-interactive
675 # usually those are non-interactive
673 return self._isatty(self.fout)
676 return self._isatty(self.fout)
674
677
675 return i
678 return i
676
679
677 def _readline(self, prompt=''):
680 def _readline(self, prompt=''):
678 if self._isatty(self.fin):
681 if self._isatty(self.fin):
679 try:
682 try:
680 # magically add command line editing support, where
683 # magically add command line editing support, where
681 # available
684 # available
682 import readline
685 import readline
683 # force demandimport to really load the module
686 # force demandimport to really load the module
684 readline.read_history_file
687 readline.read_history_file
685 # windows sometimes raises something other than ImportError
688 # windows sometimes raises something other than ImportError
686 except Exception:
689 except Exception:
687 pass
690 pass
688
691
689 # call write() so output goes through subclassed implementation
692 # call write() so output goes through subclassed implementation
690 # e.g. color extension on Windows
693 # e.g. color extension on Windows
691 self.write(prompt)
694 self.write(prompt)
692
695
693 # instead of trying to emulate raw_input, swap (self.fin,
696 # instead of trying to emulate raw_input, swap (self.fin,
694 # self.fout) with (sys.stdin, sys.stdout)
697 # self.fout) with (sys.stdin, sys.stdout)
695 oldin = sys.stdin
698 oldin = sys.stdin
696 oldout = sys.stdout
699 oldout = sys.stdout
697 sys.stdin = self.fin
700 sys.stdin = self.fin
698 sys.stdout = self.fout
701 sys.stdout = self.fout
699 # prompt ' ' must exist; otherwise readline may delete entire line
702 # prompt ' ' must exist; otherwise readline may delete entire line
700 # - http://bugs.python.org/issue12833
703 # - http://bugs.python.org/issue12833
701 line = raw_input(' ')
704 line = raw_input(' ')
702 sys.stdin = oldin
705 sys.stdin = oldin
703 sys.stdout = oldout
706 sys.stdout = oldout
704
707
705 # When stdin is in binary mode on Windows, it can cause
708 # When stdin is in binary mode on Windows, it can cause
706 # raw_input() to emit an extra trailing carriage return
709 # raw_input() to emit an extra trailing carriage return
707 if os.linesep == '\r\n' and line and line[-1] == '\r':
710 if os.linesep == '\r\n' and line and line[-1] == '\r':
708 line = line[:-1]
711 line = line[:-1]
709 return line
712 return line
710
713
711 def prompt(self, msg, default="y"):
714 def prompt(self, msg, default="y"):
712 """Prompt user with msg, read response.
715 """Prompt user with msg, read response.
713 If ui is not interactive, the default is returned.
716 If ui is not interactive, the default is returned.
714 """
717 """
715 if not self.interactive():
718 if not self.interactive():
716 self.write(msg, ' ', default, "\n")
719 self.write(msg, ' ', default, "\n")
717 return default
720 return default
718 try:
721 try:
719 r = self._readline(self.label(msg, 'ui.prompt'))
722 r = self._readline(self.label(msg, 'ui.prompt'))
720 if not r:
723 if not r:
721 r = default
724 r = default
722 if self.configbool('ui', 'promptecho'):
725 if self.configbool('ui', 'promptecho'):
723 self.write(r, "\n")
726 self.write(r, "\n")
724 return r
727 return r
725 except EOFError:
728 except EOFError:
726 raise util.Abort(_('response expected'))
729 raise util.Abort(_('response expected'))
727
730
728 @staticmethod
731 @staticmethod
729 def extractchoices(prompt):
732 def extractchoices(prompt):
730 """Extract prompt message and list of choices from specified prompt.
733 """Extract prompt message and list of choices from specified prompt.
731
734
732 This returns tuple "(message, choices)", and "choices" is the
735 This returns tuple "(message, choices)", and "choices" is the
733 list of tuple "(response character, text without &)".
736 list of tuple "(response character, text without &)".
734 """
737 """
735 parts = prompt.split('$$')
738 parts = prompt.split('$$')
736 msg = parts[0].rstrip(' ')
739 msg = parts[0].rstrip(' ')
737 choices = [p.strip(' ') for p in parts[1:]]
740 choices = [p.strip(' ') for p in parts[1:]]
738 return (msg,
741 return (msg,
739 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
742 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
740 for s in choices])
743 for s in choices])
741
744
742 def promptchoice(self, prompt, default=0):
745 def promptchoice(self, prompt, default=0):
743 """Prompt user with a message, read response, and ensure it matches
746 """Prompt user with a message, read response, and ensure it matches
744 one of the provided choices. The prompt is formatted as follows:
747 one of the provided choices. The prompt is formatted as follows:
745
748
746 "would you like fries with that (Yn)? $$ &Yes $$ &No"
749 "would you like fries with that (Yn)? $$ &Yes $$ &No"
747
750
748 The index of the choice is returned. Responses are case
751 The index of the choice is returned. Responses are case
749 insensitive. If ui is not interactive, the default is
752 insensitive. If ui is not interactive, the default is
750 returned.
753 returned.
751 """
754 """
752
755
753 msg, choices = self.extractchoices(prompt)
756 msg, choices = self.extractchoices(prompt)
754 resps = [r for r, t in choices]
757 resps = [r for r, t in choices]
755 while True:
758 while True:
756 r = self.prompt(msg, resps[default])
759 r = self.prompt(msg, resps[default])
757 if r.lower() in resps:
760 if r.lower() in resps:
758 return resps.index(r.lower())
761 return resps.index(r.lower())
759 self.write(_("unrecognized response\n"))
762 self.write(_("unrecognized response\n"))
760
763
761 def getpass(self, prompt=None, default=None):
764 def getpass(self, prompt=None, default=None):
762 if not self.interactive():
765 if not self.interactive():
763 return default
766 return default
764 try:
767 try:
765 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
768 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
766 # disable getpass() only if explicitly specified. it's still valid
769 # disable getpass() only if explicitly specified. it's still valid
767 # to interact with tty even if fin is not a tty.
770 # to interact with tty even if fin is not a tty.
768 if self.configbool('ui', 'nontty'):
771 if self.configbool('ui', 'nontty'):
769 return self.fin.readline().rstrip('\n')
772 return self.fin.readline().rstrip('\n')
770 else:
773 else:
771 return getpass.getpass('')
774 return getpass.getpass('')
772 except EOFError:
775 except EOFError:
773 raise util.Abort(_('response expected'))
776 raise util.Abort(_('response expected'))
774 def status(self, *msg, **opts):
777 def status(self, *msg, **opts):
775 '''write status message to output (if ui.quiet is False)
778 '''write status message to output (if ui.quiet is False)
776
779
777 This adds an output label of "ui.status".
780 This adds an output label of "ui.status".
778 '''
781 '''
779 if not self.quiet:
782 if not self.quiet:
780 opts['label'] = opts.get('label', '') + ' ui.status'
783 opts['label'] = opts.get('label', '') + ' ui.status'
781 self.write(*msg, **opts)
784 self.write(*msg, **opts)
782 def warn(self, *msg, **opts):
785 def warn(self, *msg, **opts):
783 '''write warning message to output (stderr)
786 '''write warning message to output (stderr)
784
787
785 This adds an output label of "ui.warning".
788 This adds an output label of "ui.warning".
786 '''
789 '''
787 opts['label'] = opts.get('label', '') + ' ui.warning'
790 opts['label'] = opts.get('label', '') + ' ui.warning'
788 self.write_err(*msg, **opts)
791 self.write_err(*msg, **opts)
789 def note(self, *msg, **opts):
792 def note(self, *msg, **opts):
790 '''write note to output (if ui.verbose is True)
793 '''write note to output (if ui.verbose is True)
791
794
792 This adds an output label of "ui.note".
795 This adds an output label of "ui.note".
793 '''
796 '''
794 if self.verbose:
797 if self.verbose:
795 opts['label'] = opts.get('label', '') + ' ui.note'
798 opts['label'] = opts.get('label', '') + ' ui.note'
796 self.write(*msg, **opts)
799 self.write(*msg, **opts)
797 def debug(self, *msg, **opts):
800 def debug(self, *msg, **opts):
798 '''write debug message to output (if ui.debugflag is True)
801 '''write debug message to output (if ui.debugflag is True)
799
802
800 This adds an output label of "ui.debug".
803 This adds an output label of "ui.debug".
801 '''
804 '''
802 if self.debugflag:
805 if self.debugflag:
803 opts['label'] = opts.get('label', '') + ' ui.debug'
806 opts['label'] = opts.get('label', '') + ' ui.debug'
804 self.write(*msg, **opts)
807 self.write(*msg, **opts)
805 def edit(self, text, user, extra={}, editform=None):
808 def edit(self, text, user, extra={}, editform=None):
806 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
809 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
807 text=True)
810 text=True)
808 try:
811 try:
809 f = os.fdopen(fd, "w")
812 f = os.fdopen(fd, "w")
810 f.write(text)
813 f.write(text)
811 f.close()
814 f.close()
812
815
813 environ = {'HGUSER': user}
816 environ = {'HGUSER': user}
814 if 'transplant_source' in extra:
817 if 'transplant_source' in extra:
815 environ.update({'HGREVISION': hex(extra['transplant_source'])})
818 environ.update({'HGREVISION': hex(extra['transplant_source'])})
816 for label in ('intermediate-source', 'source', 'rebase_source'):
819 for label in ('intermediate-source', 'source', 'rebase_source'):
817 if label in extra:
820 if label in extra:
818 environ.update({'HGREVISION': extra[label]})
821 environ.update({'HGREVISION': extra[label]})
819 break
822 break
820 if editform:
823 if editform:
821 environ.update({'HGEDITFORM': editform})
824 environ.update({'HGEDITFORM': editform})
822
825
823 editor = self.geteditor()
826 editor = self.geteditor()
824
827
825 self.system("%s \"%s\"" % (editor, name),
828 self.system("%s \"%s\"" % (editor, name),
826 environ=environ,
829 environ=environ,
827 onerr=util.Abort, errprefix=_("edit failed"))
830 onerr=util.Abort, errprefix=_("edit failed"))
828
831
829 f = open(name)
832 f = open(name)
830 t = f.read()
833 t = f.read()
831 f.close()
834 f.close()
832 finally:
835 finally:
833 os.unlink(name)
836 os.unlink(name)
834
837
835 return t
838 return t
836
839
837 def system(self, cmd, environ={}, cwd=None, onerr=None, errprefix=None):
840 def system(self, cmd, environ={}, cwd=None, onerr=None, errprefix=None):
838 '''execute shell command with appropriate output stream. command
841 '''execute shell command with appropriate output stream. command
839 output will be redirected if fout is not stdout.
842 output will be redirected if fout is not stdout.
840 '''
843 '''
841 out = self.fout
844 out = self.fout
842 if util.any(s[1] for s in self._bufferstates):
845 if util.any(s[1] for s in self._bufferstates):
843 out = self
846 out = self
844 return util.system(cmd, environ=environ, cwd=cwd, onerr=onerr,
847 return util.system(cmd, environ=environ, cwd=cwd, onerr=onerr,
845 errprefix=errprefix, out=out)
848 errprefix=errprefix, out=out)
846
849
847 def traceback(self, exc=None, force=False):
850 def traceback(self, exc=None, force=False):
848 '''print exception traceback if traceback printing enabled or forced.
851 '''print exception traceback if traceback printing enabled or forced.
849 only to call in exception handler. returns true if traceback
852 only to call in exception handler. returns true if traceback
850 printed.'''
853 printed.'''
851 if self.tracebackflag or force:
854 if self.tracebackflag or force:
852 if exc is None:
855 if exc is None:
853 exc = sys.exc_info()
856 exc = sys.exc_info()
854 cause = getattr(exc[1], 'cause', None)
857 cause = getattr(exc[1], 'cause', None)
855
858
856 if cause is not None:
859 if cause is not None:
857 causetb = traceback.format_tb(cause[2])
860 causetb = traceback.format_tb(cause[2])
858 exctb = traceback.format_tb(exc[2])
861 exctb = traceback.format_tb(exc[2])
859 exconly = traceback.format_exception_only(cause[0], cause[1])
862 exconly = traceback.format_exception_only(cause[0], cause[1])
860
863
861 # exclude frame where 'exc' was chained and rethrown from exctb
864 # exclude frame where 'exc' was chained and rethrown from exctb
862 self.write_err('Traceback (most recent call last):\n',
865 self.write_err('Traceback (most recent call last):\n',
863 ''.join(exctb[:-1]),
866 ''.join(exctb[:-1]),
864 ''.join(causetb),
867 ''.join(causetb),
865 ''.join(exconly))
868 ''.join(exconly))
866 else:
869 else:
867 traceback.print_exception(exc[0], exc[1], exc[2],
870 traceback.print_exception(exc[0], exc[1], exc[2],
868 file=self.ferr)
871 file=self.ferr)
869 return self.tracebackflag or force
872 return self.tracebackflag or force
870
873
871 def geteditor(self):
874 def geteditor(self):
872 '''return editor to use'''
875 '''return editor to use'''
873 if sys.platform == 'plan9':
876 if sys.platform == 'plan9':
874 # vi is the MIPS instruction simulator on Plan 9. We
877 # vi is the MIPS instruction simulator on Plan 9. We
875 # instead default to E to plumb commit messages to
878 # instead default to E to plumb commit messages to
876 # avoid confusion.
879 # avoid confusion.
877 editor = 'E'
880 editor = 'E'
878 else:
881 else:
879 editor = 'vi'
882 editor = 'vi'
880 return (os.environ.get("HGEDITOR") or
883 return (os.environ.get("HGEDITOR") or
881 self.config("ui", "editor") or
884 self.config("ui", "editor") or
882 os.environ.get("VISUAL") or
885 os.environ.get("VISUAL") or
883 os.environ.get("EDITOR", editor))
886 os.environ.get("EDITOR", editor))
884
887
885 def progress(self, topic, pos, item="", unit="", total=None):
888 def progress(self, topic, pos, item="", unit="", total=None):
886 '''show a progress message
889 '''show a progress message
887
890
888 With stock hg, this is simply a debug message that is hidden
891 With stock hg, this is simply a debug message that is hidden
889 by default, but with extensions or GUI tools it may be
892 by default, but with extensions or GUI tools it may be
890 visible. 'topic' is the current operation, 'item' is a
893 visible. 'topic' is the current operation, 'item' is a
891 non-numeric marker of the current position (i.e. the currently
894 non-numeric marker of the current position (i.e. the currently
892 in-process file), 'pos' is the current numeric position (i.e.
895 in-process file), 'pos' is the current numeric position (i.e.
893 revision, bytes, etc.), unit is a corresponding unit label,
896 revision, bytes, etc.), unit is a corresponding unit label,
894 and total is the highest expected pos.
897 and total is the highest expected pos.
895
898
896 Multiple nested topics may be active at a time.
899 Multiple nested topics may be active at a time.
897
900
898 All topics should be marked closed by setting pos to None at
901 All topics should be marked closed by setting pos to None at
899 termination.
902 termination.
900 '''
903 '''
901
904
902 if pos is None or not self.debugflag:
905 if pos is None or not self.debugflag:
903 return
906 return
904
907
905 if unit:
908 if unit:
906 unit = ' ' + unit
909 unit = ' ' + unit
907 if item:
910 if item:
908 item = ' ' + item
911 item = ' ' + item
909
912
910 if total:
913 if total:
911 pct = 100.0 * pos / total
914 pct = 100.0 * pos / total
912 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
915 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
913 % (topic, item, pos, total, unit, pct))
916 % (topic, item, pos, total, unit, pct))
914 else:
917 else:
915 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
918 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
916
919
917 def log(self, service, *msg, **opts):
920 def log(self, service, *msg, **opts):
918 '''hook for logging facility extensions
921 '''hook for logging facility extensions
919
922
920 service should be a readily-identifiable subsystem, which will
923 service should be a readily-identifiable subsystem, which will
921 allow filtering.
924 allow filtering.
922 message should be a newline-terminated string to log.
925 message should be a newline-terminated string to log.
923 '''
926 '''
924 pass
927 pass
925
928
926 def label(self, msg, label):
929 def label(self, msg, label):
927 '''style msg based on supplied label
930 '''style msg based on supplied label
928
931
929 Like ui.write(), this just returns msg unchanged, but extensions
932 Like ui.write(), this just returns msg unchanged, but extensions
930 and GUI tools can override it to allow styling output without
933 and GUI tools can override it to allow styling output without
931 writing it.
934 writing it.
932
935
933 ui.write(s, 'label') is equivalent to
936 ui.write(s, 'label') is equivalent to
934 ui.write(ui.label(s, 'label')).
937 ui.write(ui.label(s, 'label')).
935 '''
938 '''
936 return msg
939 return msg
937
940
938 class paths(dict):
941 class paths(dict):
939 """Represents a collection of paths and their configs.
942 """Represents a collection of paths and their configs.
940
943
941 Data is initially derived from ui instances and the config files they have
944 Data is initially derived from ui instances and the config files they have
942 loaded.
945 loaded.
943 """
946 """
944 def __init__(self, ui):
947 def __init__(self, ui):
945 dict.__init__(self)
948 dict.__init__(self)
946
949
947 for name, loc in ui.configitems('paths'):
950 for name, loc in ui.configitems('paths'):
948 # No location is the same as not existing.
951 # No location is the same as not existing.
949 if not loc:
952 if not loc:
950 continue
953 continue
951 self[name] = path(name, rawloc=loc)
954 self[name] = path(name, rawloc=loc)
952
955
953 def getpath(self, name, default=None):
956 def getpath(self, name, default=None):
954 """Return a ``path`` for the specified name, falling back to a default.
957 """Return a ``path`` for the specified name, falling back to a default.
955
958
956 Returns the first of ``name`` or ``default`` that is present, or None
959 Returns the first of ``name`` or ``default`` that is present, or None
957 if neither is present.
960 if neither is present.
958 """
961 """
959 try:
962 try:
960 return self[name]
963 return self[name]
961 except KeyError:
964 except KeyError:
962 if default is not None:
965 if default is not None:
963 try:
966 try:
964 return self[default]
967 return self[default]
965 except KeyError:
968 except KeyError:
966 pass
969 pass
967
970
968 return None
971 return None
969
972
970 class path(object):
973 class path(object):
971 """Represents an individual path and its configuration."""
974 """Represents an individual path and its configuration."""
972
975
973 def __init__(self, name, rawloc=None):
976 def __init__(self, name, rawloc=None):
974 """Construct a path from its config options.
977 """Construct a path from its config options.
975
978
976 ``name`` is the symbolic name of the path.
979 ``name`` is the symbolic name of the path.
977 ``rawloc`` is the raw location, as defined in the config.
980 ``rawloc`` is the raw location, as defined in the config.
978 """
981 """
979 self.name = name
982 self.name = name
980 # We'll do more intelligent things with rawloc in the future.
983 # We'll do more intelligent things with rawloc in the future.
981 self.loc = rawloc
984 self.loc = rawloc
@@ -1,1541 +1,1595 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3
3
4 $ try() {
4 $ try() {
5 > hg debugrevspec --debug "$@"
5 > hg debugrevspec --debug "$@"
6 > }
6 > }
7
7
8 $ log() {
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
9 > hg log --template '{rev}\n' -r "$1"
10 > }
10 > }
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg branch a
16 $ hg branch a
17 marked working directory as branch a
17 marked working directory as branch a
18 (branches are permanent and global, did you want a bookmark?)
18 (branches are permanent and global, did you want a bookmark?)
19 $ hg ci -Aqm0
19 $ hg ci -Aqm0
20
20
21 $ echo b > b
21 $ echo b > b
22 $ hg branch b
22 $ hg branch b
23 marked working directory as branch b
23 marked working directory as branch b
24 (branches are permanent and global, did you want a bookmark?)
24 (branches are permanent and global, did you want a bookmark?)
25 $ hg ci -Aqm1
25 $ hg ci -Aqm1
26
26
27 $ rm a
27 $ rm a
28 $ hg branch a-b-c-
28 $ hg branch a-b-c-
29 marked working directory as branch a-b-c-
29 marked working directory as branch a-b-c-
30 (branches are permanent and global, did you want a bookmark?)
30 (branches are permanent and global, did you want a bookmark?)
31 $ hg ci -Aqm2 -u Bob
31 $ hg ci -Aqm2 -u Bob
32
32
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
33 $ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
34 2
34 2
35 $ hg log -r "extra('branch')" --template '{rev}\n'
35 $ hg log -r "extra('branch')" --template '{rev}\n'
36 0
36 0
37 1
37 1
38 2
38 2
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
39 $ hg log -r "extra('branch', 're:a')" --template '{rev} {branch}\n'
40 0 a
40 0 a
41 2 a-b-c-
41 2 a-b-c-
42
42
43 $ hg co 1
43 $ hg co 1
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch +a+b+c+
45 $ hg branch +a+b+c+
46 marked working directory as branch +a+b+c+
46 marked working directory as branch +a+b+c+
47 (branches are permanent and global, did you want a bookmark?)
47 (branches are permanent and global, did you want a bookmark?)
48 $ hg ci -Aqm3
48 $ hg ci -Aqm3
49
49
50 $ hg co 2 # interleave
50 $ hg co 2 # interleave
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
52 $ echo bb > b
52 $ echo bb > b
53 $ hg branch -- -a-b-c-
53 $ hg branch -- -a-b-c-
54 marked working directory as branch -a-b-c-
54 marked working directory as branch -a-b-c-
55 (branches are permanent and global, did you want a bookmark?)
55 (branches are permanent and global, did you want a bookmark?)
56 $ hg ci -Aqm4 -d "May 12 2005"
56 $ hg ci -Aqm4 -d "May 12 2005"
57
57
58 $ hg co 3
58 $ hg co 3
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 $ hg branch !a/b/c/
60 $ hg branch !a/b/c/
61 marked working directory as branch !a/b/c/
61 marked working directory as branch !a/b/c/
62 (branches are permanent and global, did you want a bookmark?)
62 (branches are permanent and global, did you want a bookmark?)
63 $ hg ci -Aqm"5 bug"
63 $ hg ci -Aqm"5 bug"
64
64
65 $ hg merge 4
65 $ hg merge 4
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
67 (branch merge, don't forget to commit)
67 (branch merge, don't forget to commit)
68 $ hg branch _a_b_c_
68 $ hg branch _a_b_c_
69 marked working directory as branch _a_b_c_
69 marked working directory as branch _a_b_c_
70 (branches are permanent and global, did you want a bookmark?)
70 (branches are permanent and global, did you want a bookmark?)
71 $ hg ci -Aqm"6 issue619"
71 $ hg ci -Aqm"6 issue619"
72
72
73 $ hg branch .a.b.c.
73 $ hg branch .a.b.c.
74 marked working directory as branch .a.b.c.
74 marked working directory as branch .a.b.c.
75 (branches are permanent and global, did you want a bookmark?)
75 (branches are permanent and global, did you want a bookmark?)
76 $ hg ci -Aqm7
76 $ hg ci -Aqm7
77
77
78 $ hg branch all
78 $ hg branch all
79 marked working directory as branch all
79 marked working directory as branch all
80 (branches are permanent and global, did you want a bookmark?)
80 (branches are permanent and global, did you want a bookmark?)
81
81
82 $ hg co 4
82 $ hg co 4
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 $ hg branch Γ©
84 $ hg branch Γ©
85 marked working directory as branch \xc3\xa9 (esc)
85 marked working directory as branch \xc3\xa9 (esc)
86 (branches are permanent and global, did you want a bookmark?)
86 (branches are permanent and global, did you want a bookmark?)
87 $ hg ci -Aqm9
87 $ hg ci -Aqm9
88
88
89 $ hg tag -r6 1.0
89 $ hg tag -r6 1.0
90
90
91 $ hg clone --quiet -U -r 7 . ../remote1
91 $ hg clone --quiet -U -r 7 . ../remote1
92 $ hg clone --quiet -U -r 8 . ../remote2
92 $ hg clone --quiet -U -r 8 . ../remote2
93 $ echo "[paths]" >> .hg/hgrc
93 $ echo "[paths]" >> .hg/hgrc
94 $ echo "default = ../remote1" >> .hg/hgrc
94 $ echo "default = ../remote1" >> .hg/hgrc
95
95
96 trivial
96 trivial
97
97
98 $ try 0:1
98 $ try 0:1
99 (range
99 (range
100 ('symbol', '0')
100 ('symbol', '0')
101 ('symbol', '1'))
101 ('symbol', '1'))
102 * set:
102 * set:
103 <spanset+ 0:1>
103 <spanset+ 0:1>
104 0
104 0
105 1
105 1
106 $ try 3::6
106 $ try 3::6
107 (dagrange
107 (dagrange
108 ('symbol', '3')
108 ('symbol', '3')
109 ('symbol', '6'))
109 ('symbol', '6'))
110 * set:
110 * set:
111 <baseset [3, 5, 6]>
111 <baseset [3, 5, 6]>
112 3
112 3
113 5
113 5
114 6
114 6
115 $ try '0|1|2'
115 $ try '0|1|2'
116 (or
116 (or
117 (or
117 (or
118 ('symbol', '0')
118 ('symbol', '0')
119 ('symbol', '1'))
119 ('symbol', '1'))
120 ('symbol', '2'))
120 ('symbol', '2'))
121 * set:
121 * set:
122 <addset
122 <addset
123 <addset
123 <addset
124 <baseset [0]>,
124 <baseset [0]>,
125 <baseset [1]>>,
125 <baseset [1]>>,
126 <baseset [2]>>
126 <baseset [2]>>
127 0
127 0
128 1
128 1
129 2
129 2
130
130
131 names that should work without quoting
131 names that should work without quoting
132
132
133 $ try a
133 $ try a
134 ('symbol', 'a')
134 ('symbol', 'a')
135 * set:
135 * set:
136 <baseset [0]>
136 <baseset [0]>
137 0
137 0
138 $ try b-a
138 $ try b-a
139 (minus
139 (minus
140 ('symbol', 'b')
140 ('symbol', 'b')
141 ('symbol', 'a'))
141 ('symbol', 'a'))
142 * set:
142 * set:
143 <filteredset
143 <filteredset
144 <baseset [1]>>
144 <baseset [1]>>
145 1
145 1
146 $ try _a_b_c_
146 $ try _a_b_c_
147 ('symbol', '_a_b_c_')
147 ('symbol', '_a_b_c_')
148 * set:
148 * set:
149 <baseset [6]>
149 <baseset [6]>
150 6
150 6
151 $ try _a_b_c_-a
151 $ try _a_b_c_-a
152 (minus
152 (minus
153 ('symbol', '_a_b_c_')
153 ('symbol', '_a_b_c_')
154 ('symbol', 'a'))
154 ('symbol', 'a'))
155 * set:
155 * set:
156 <filteredset
156 <filteredset
157 <baseset [6]>>
157 <baseset [6]>>
158 6
158 6
159 $ try .a.b.c.
159 $ try .a.b.c.
160 ('symbol', '.a.b.c.')
160 ('symbol', '.a.b.c.')
161 * set:
161 * set:
162 <baseset [7]>
162 <baseset [7]>
163 7
163 7
164 $ try .a.b.c.-a
164 $ try .a.b.c.-a
165 (minus
165 (minus
166 ('symbol', '.a.b.c.')
166 ('symbol', '.a.b.c.')
167 ('symbol', 'a'))
167 ('symbol', 'a'))
168 * set:
168 * set:
169 <filteredset
169 <filteredset
170 <baseset [7]>>
170 <baseset [7]>>
171 7
171 7
172 $ try -- '-a-b-c-' # complains
172 $ try -- '-a-b-c-' # complains
173 hg: parse error at 7: not a prefix: end
173 hg: parse error at 7: not a prefix: end
174 [255]
174 [255]
175 $ log -a-b-c- # succeeds with fallback
175 $ log -a-b-c- # succeeds with fallback
176 4
176 4
177
177
178 $ try -- -a-b-c--a # complains
178 $ try -- -a-b-c--a # complains
179 (minus
179 (minus
180 (minus
180 (minus
181 (minus
181 (minus
182 (negate
182 (negate
183 ('symbol', 'a'))
183 ('symbol', 'a'))
184 ('symbol', 'b'))
184 ('symbol', 'b'))
185 ('symbol', 'c'))
185 ('symbol', 'c'))
186 (negate
186 (negate
187 ('symbol', 'a')))
187 ('symbol', 'a')))
188 abort: unknown revision '-a'!
188 abort: unknown revision '-a'!
189 [255]
189 [255]
190 $ try Γ©
190 $ try Γ©
191 ('symbol', '\xc3\xa9')
191 ('symbol', '\xc3\xa9')
192 * set:
192 * set:
193 <baseset [9]>
193 <baseset [9]>
194 9
194 9
195
195
196 no quoting needed
196 no quoting needed
197
197
198 $ log ::a-b-c-
198 $ log ::a-b-c-
199 0
199 0
200 1
200 1
201 2
201 2
202
202
203 quoting needed
203 quoting needed
204
204
205 $ try '"-a-b-c-"-a'
205 $ try '"-a-b-c-"-a'
206 (minus
206 (minus
207 ('string', '-a-b-c-')
207 ('string', '-a-b-c-')
208 ('symbol', 'a'))
208 ('symbol', 'a'))
209 * set:
209 * set:
210 <filteredset
210 <filteredset
211 <baseset [4]>>
211 <baseset [4]>>
212 4
212 4
213
213
214 $ log '1 or 2'
214 $ log '1 or 2'
215 1
215 1
216 2
216 2
217 $ log '1|2'
217 $ log '1|2'
218 1
218 1
219 2
219 2
220 $ log '1 and 2'
220 $ log '1 and 2'
221 $ log '1&2'
221 $ log '1&2'
222 $ try '1&2|3' # precedence - and is higher
222 $ try '1&2|3' # precedence - and is higher
223 (or
223 (or
224 (and
224 (and
225 ('symbol', '1')
225 ('symbol', '1')
226 ('symbol', '2'))
226 ('symbol', '2'))
227 ('symbol', '3'))
227 ('symbol', '3'))
228 * set:
228 * set:
229 <addset
229 <addset
230 <baseset []>,
230 <baseset []>,
231 <baseset [3]>>
231 <baseset [3]>>
232 3
232 3
233 $ try '1|2&3'
233 $ try '1|2&3'
234 (or
234 (or
235 ('symbol', '1')
235 ('symbol', '1')
236 (and
236 (and
237 ('symbol', '2')
237 ('symbol', '2')
238 ('symbol', '3')))
238 ('symbol', '3')))
239 * set:
239 * set:
240 <addset
240 <addset
241 <baseset [1]>,
241 <baseset [1]>,
242 <baseset []>>
242 <baseset []>>
243 1
243 1
244 $ try '1&2&3' # associativity
244 $ try '1&2&3' # associativity
245 (and
245 (and
246 (and
246 (and
247 ('symbol', '1')
247 ('symbol', '1')
248 ('symbol', '2'))
248 ('symbol', '2'))
249 ('symbol', '3'))
249 ('symbol', '3'))
250 * set:
250 * set:
251 <baseset []>
251 <baseset []>
252 $ try '1|(2|3)'
252 $ try '1|(2|3)'
253 (or
253 (or
254 ('symbol', '1')
254 ('symbol', '1')
255 (group
255 (group
256 (or
256 (or
257 ('symbol', '2')
257 ('symbol', '2')
258 ('symbol', '3'))))
258 ('symbol', '3'))))
259 * set:
259 * set:
260 <addset
260 <addset
261 <baseset [1]>,
261 <baseset [1]>,
262 <addset
262 <addset
263 <baseset [2]>,
263 <baseset [2]>,
264 <baseset [3]>>>
264 <baseset [3]>>>
265 1
265 1
266 2
266 2
267 3
267 3
268 $ log '1.0' # tag
268 $ log '1.0' # tag
269 6
269 6
270 $ log 'a' # branch
270 $ log 'a' # branch
271 0
271 0
272 $ log '2785f51ee'
272 $ log '2785f51ee'
273 0
273 0
274 $ log 'date(2005)'
274 $ log 'date(2005)'
275 4
275 4
276 $ log 'date(this is a test)'
276 $ log 'date(this is a test)'
277 hg: parse error at 10: unexpected token: symbol
277 hg: parse error at 10: unexpected token: symbol
278 [255]
278 [255]
279 $ log 'date()'
279 $ log 'date()'
280 hg: parse error: date requires a string
280 hg: parse error: date requires a string
281 [255]
281 [255]
282 $ log 'date'
282 $ log 'date'
283 hg: parse error: can't use date here
283 hg: parse error: can't use date here
284 [255]
284 [255]
285 $ log 'date('
285 $ log 'date('
286 hg: parse error at 5: not a prefix: end
286 hg: parse error at 5: not a prefix: end
287 [255]
287 [255]
288 $ log 'date(tip)'
288 $ log 'date(tip)'
289 abort: invalid date: 'tip'
289 abort: invalid date: 'tip'
290 [255]
290 [255]
291 $ log '"date"'
291 $ log '"date"'
292 abort: unknown revision 'date'!
292 abort: unknown revision 'date'!
293 [255]
293 [255]
294 $ log 'date(2005) and 1::'
294 $ log 'date(2005) and 1::'
295 4
295 4
296
296
297 ancestor can accept 0 or more arguments
297 ancestor can accept 0 or more arguments
298
298
299 $ log 'ancestor()'
299 $ log 'ancestor()'
300 $ log 'ancestor(1)'
300 $ log 'ancestor(1)'
301 1
301 1
302 $ log 'ancestor(4,5)'
302 $ log 'ancestor(4,5)'
303 1
303 1
304 $ log 'ancestor(4,5) and 4'
304 $ log 'ancestor(4,5) and 4'
305 $ log 'ancestor(0,0,1,3)'
305 $ log 'ancestor(0,0,1,3)'
306 0
306 0
307 $ log 'ancestor(3,1,5,3,5,1)'
307 $ log 'ancestor(3,1,5,3,5,1)'
308 1
308 1
309 $ log 'ancestor(0,1,3,5)'
309 $ log 'ancestor(0,1,3,5)'
310 0
310 0
311 $ log 'ancestor(1,2,3,4,5)'
311 $ log 'ancestor(1,2,3,4,5)'
312 1
312 1
313 $ log 'ancestors(5)'
313 $ log 'ancestors(5)'
314 0
314 0
315 1
315 1
316 3
316 3
317 5
317 5
318 $ log 'ancestor(ancestors(5))'
318 $ log 'ancestor(ancestors(5))'
319 0
319 0
320 $ log 'author(bob)'
320 $ log 'author(bob)'
321 2
321 2
322 $ log 'author("re:bob|test")'
322 $ log 'author("re:bob|test")'
323 0
323 0
324 1
324 1
325 2
325 2
326 3
326 3
327 4
327 4
328 5
328 5
329 6
329 6
330 7
330 7
331 8
331 8
332 9
332 9
333 $ log 'branch(Γ©)'
333 $ log 'branch(Γ©)'
334 8
334 8
335 9
335 9
336 $ log 'branch(a)'
336 $ log 'branch(a)'
337 0
337 0
338 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
338 $ hg log -r 'branch("re:a")' --template '{rev} {branch}\n'
339 0 a
339 0 a
340 2 a-b-c-
340 2 a-b-c-
341 3 +a+b+c+
341 3 +a+b+c+
342 4 -a-b-c-
342 4 -a-b-c-
343 5 !a/b/c/
343 5 !a/b/c/
344 6 _a_b_c_
344 6 _a_b_c_
345 7 .a.b.c.
345 7 .a.b.c.
346 $ log 'children(ancestor(4,5))'
346 $ log 'children(ancestor(4,5))'
347 2
347 2
348 3
348 3
349 $ log 'closed()'
349 $ log 'closed()'
350 $ log 'contains(a)'
350 $ log 'contains(a)'
351 0
351 0
352 1
352 1
353 3
353 3
354 5
354 5
355 $ log 'contains("../repo/a")'
355 $ log 'contains("../repo/a")'
356 0
356 0
357 1
357 1
358 3
358 3
359 5
359 5
360 $ log 'desc(B)'
360 $ log 'desc(B)'
361 5
361 5
362 $ log 'descendants(2 or 3)'
362 $ log 'descendants(2 or 3)'
363 2
363 2
364 3
364 3
365 4
365 4
366 5
366 5
367 6
367 6
368 7
368 7
369 8
369 8
370 9
370 9
371 $ log 'file("b*")'
371 $ log 'file("b*")'
372 1
372 1
373 4
373 4
374 $ log 'filelog("b")'
374 $ log 'filelog("b")'
375 1
375 1
376 4
376 4
377 $ log 'filelog("../repo/b")'
377 $ log 'filelog("../repo/b")'
378 1
378 1
379 4
379 4
380 $ log 'follow()'
380 $ log 'follow()'
381 0
381 0
382 1
382 1
383 2
383 2
384 4
384 4
385 8
385 8
386 9
386 9
387 $ log 'grep("issue\d+")'
387 $ log 'grep("issue\d+")'
388 6
388 6
389 $ try 'grep("(")' # invalid regular expression
389 $ try 'grep("(")' # invalid regular expression
390 (func
390 (func
391 ('symbol', 'grep')
391 ('symbol', 'grep')
392 ('string', '('))
392 ('string', '('))
393 hg: parse error: invalid match pattern: unbalanced parenthesis
393 hg: parse error: invalid match pattern: unbalanced parenthesis
394 [255]
394 [255]
395 $ try 'grep("\bissue\d+")'
395 $ try 'grep("\bissue\d+")'
396 (func
396 (func
397 ('symbol', 'grep')
397 ('symbol', 'grep')
398 ('string', '\x08issue\\d+'))
398 ('string', '\x08issue\\d+'))
399 * set:
399 * set:
400 <filteredset
400 <filteredset
401 <fullreposet+ 0:9>>
401 <fullreposet+ 0:9>>
402 $ try 'grep(r"\bissue\d+")'
402 $ try 'grep(r"\bissue\d+")'
403 (func
403 (func
404 ('symbol', 'grep')
404 ('symbol', 'grep')
405 ('string', '\\bissue\\d+'))
405 ('string', '\\bissue\\d+'))
406 * set:
406 * set:
407 <filteredset
407 <filteredset
408 <fullreposet+ 0:9>>
408 <fullreposet+ 0:9>>
409 6
409 6
410 $ try 'grep(r"\")'
410 $ try 'grep(r"\")'
411 hg: parse error at 7: unterminated string
411 hg: parse error at 7: unterminated string
412 [255]
412 [255]
413 $ log 'head()'
413 $ log 'head()'
414 0
414 0
415 1
415 1
416 2
416 2
417 3
417 3
418 4
418 4
419 5
419 5
420 6
420 6
421 7
421 7
422 9
422 9
423 $ log 'heads(6::)'
423 $ log 'heads(6::)'
424 7
424 7
425 $ log 'keyword(issue)'
425 $ log 'keyword(issue)'
426 6
426 6
427 $ log 'keyword("test a")'
427 $ log 'keyword("test a")'
428 $ log 'limit(head(), 1)'
428 $ log 'limit(head(), 1)'
429 0
429 0
430 $ log 'matching(6)'
430 $ log 'matching(6)'
431 6
431 6
432 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
432 $ log 'matching(6:7, "phase parents user date branch summary files description substate")'
433 6
433 6
434 7
434 7
435
435
436 Testing min and max
436 Testing min and max
437
437
438 max: simple
438 max: simple
439
439
440 $ log 'max(contains(a))'
440 $ log 'max(contains(a))'
441 5
441 5
442
442
443 max: simple on unordered set)
443 max: simple on unordered set)
444
444
445 $ log 'max((4+0+2+5+7) and contains(a))'
445 $ log 'max((4+0+2+5+7) and contains(a))'
446 5
446 5
447
447
448 max: no result
448 max: no result
449
449
450 $ log 'max(contains(stringthatdoesnotappearanywhere))'
450 $ log 'max(contains(stringthatdoesnotappearanywhere))'
451
451
452 max: no result on unordered set
452 max: no result on unordered set
453
453
454 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
454 $ log 'max((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
455
455
456 min: simple
456 min: simple
457
457
458 $ log 'min(contains(a))'
458 $ log 'min(contains(a))'
459 0
459 0
460
460
461 min: simple on unordered set
461 min: simple on unordered set
462
462
463 $ log 'min((4+0+2+5+7) and contains(a))'
463 $ log 'min((4+0+2+5+7) and contains(a))'
464 0
464 0
465
465
466 min: empty
466 min: empty
467
467
468 $ log 'min(contains(stringthatdoesnotappearanywhere))'
468 $ log 'min(contains(stringthatdoesnotappearanywhere))'
469
469
470 min: empty on unordered set
470 min: empty on unordered set
471
471
472 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
472 $ log 'min((4+0+2+5+7) and contains(stringthatdoesnotappearanywhere))'
473
473
474
474
475 $ log 'merge()'
475 $ log 'merge()'
476 6
476 6
477 $ log 'branchpoint()'
477 $ log 'branchpoint()'
478 1
478 1
479 4
479 4
480 $ log 'modifies(b)'
480 $ log 'modifies(b)'
481 4
481 4
482 $ log 'modifies("path:b")'
482 $ log 'modifies("path:b")'
483 4
483 4
484 $ log 'modifies("*")'
484 $ log 'modifies("*")'
485 4
485 4
486 6
486 6
487 $ log 'modifies("set:modified()")'
487 $ log 'modifies("set:modified()")'
488 4
488 4
489 $ log 'id(5)'
489 $ log 'id(5)'
490 2
490 2
491 $ log 'only(9)'
491 $ log 'only(9)'
492 8
492 8
493 9
493 9
494 $ log 'only(8)'
494 $ log 'only(8)'
495 8
495 8
496 $ log 'only(9, 5)'
496 $ log 'only(9, 5)'
497 2
497 2
498 4
498 4
499 8
499 8
500 9
500 9
501 $ log 'only(7 + 9, 5 + 2)'
501 $ log 'only(7 + 9, 5 + 2)'
502 4
502 4
503 6
503 6
504 7
504 7
505 8
505 8
506 9
506 9
507
507
508 Test empty set input
508 Test empty set input
509 $ log 'only(p2())'
509 $ log 'only(p2())'
510 $ log 'only(p1(), p2())'
510 $ log 'only(p1(), p2())'
511 0
511 0
512 1
512 1
513 2
513 2
514 4
514 4
515 8
515 8
516 9
516 9
517
517
518 Test '%' operator
518 Test '%' operator
519
519
520 $ log '9%'
520 $ log '9%'
521 8
521 8
522 9
522 9
523 $ log '9%5'
523 $ log '9%5'
524 2
524 2
525 4
525 4
526 8
526 8
527 9
527 9
528 $ log '(7 + 9)%(5 + 2)'
528 $ log '(7 + 9)%(5 + 2)'
529 4
529 4
530 6
530 6
531 7
531 7
532 8
532 8
533 9
533 9
534
534
535 Test the order of operations
535 Test the order of operations
536
536
537 $ log '7 + 9%5 + 2'
537 $ log '7 + 9%5 + 2'
538 7
538 7
539 2
539 2
540 4
540 4
541 8
541 8
542 9
542 9
543
543
544 Test explicit numeric revision
544 Test explicit numeric revision
545 $ log 'rev(-2)'
545 $ log 'rev(-2)'
546 $ log 'rev(-1)'
546 $ log 'rev(-1)'
547 -1
547 -1
548 $ log 'rev(0)'
548 $ log 'rev(0)'
549 0
549 0
550 $ log 'rev(9)'
550 $ log 'rev(9)'
551 9
551 9
552 $ log 'rev(10)'
552 $ log 'rev(10)'
553 $ log 'rev(tip)'
553 $ log 'rev(tip)'
554 hg: parse error: rev expects a number
554 hg: parse error: rev expects a number
555 [255]
555 [255]
556
556
557 Test null revision
557 Test null revision
558 $ log '(null)'
558 $ log '(null)'
559 -1
559 -1
560 $ log '(null:0)'
560 $ log '(null:0)'
561 -1
561 -1
562 0
562 0
563 $ log '(0:null)'
563 $ log '(0:null)'
564 0
564 0
565 -1
565 -1
566 $ log 'null::0'
566 $ log 'null::0'
567 -1
567 -1
568 0
568 0
569 $ log 'null:tip - 0:'
569 $ log 'null:tip - 0:'
570 -1
570 -1
571 $ log 'null: and null::' | head -1
571 $ log 'null: and null::' | head -1
572 -1
572 -1
573 $ log 'null: or 0:' | head -2
573 $ log 'null: or 0:' | head -2
574 -1
574 -1
575 0
575 0
576 $ log 'ancestors(null)'
576 $ log 'ancestors(null)'
577 -1
577 -1
578 $ log 'reverse(null:)' | tail -2
578 $ log 'reverse(null:)' | tail -2
579 0
579 0
580 -1
580 -1
581 $ log 'first(null:)'
581 $ log 'first(null:)'
582 -1
582 -1
583 $ log 'min(null:)'
583 $ log 'min(null:)'
584 -1
584 -1
585 $ log 'tip:null and all()' | tail -2
585 $ log 'tip:null and all()' | tail -2
586 1
586 1
587 0
587 0
588
588
589 Test working-directory revision
589 Test working-directory revision
590 $ hg debugrevspec 'wdir()'
590 $ hg debugrevspec 'wdir()'
591 None
591 None
592 $ hg debugrevspec 'tip or wdir()'
592 $ hg debugrevspec 'tip or wdir()'
593 9
593 9
594 None
594 None
595 $ hg debugrevspec '0:tip and wdir()'
595 $ hg debugrevspec '0:tip and wdir()'
596
596
597 $ log 'outgoing()'
597 $ log 'outgoing()'
598 8
598 8
599 9
599 9
600 $ log 'outgoing("../remote1")'
600 $ log 'outgoing("../remote1")'
601 8
601 8
602 9
602 9
603 $ log 'outgoing("../remote2")'
603 $ log 'outgoing("../remote2")'
604 3
604 3
605 5
605 5
606 6
606 6
607 7
607 7
608 9
608 9
609 $ log 'p1(merge())'
609 $ log 'p1(merge())'
610 5
610 5
611 $ log 'p2(merge())'
611 $ log 'p2(merge())'
612 4
612 4
613 $ log 'parents(merge())'
613 $ log 'parents(merge())'
614 4
614 4
615 5
615 5
616 $ log 'p1(branchpoint())'
616 $ log 'p1(branchpoint())'
617 0
617 0
618 2
618 2
619 $ log 'p2(branchpoint())'
619 $ log 'p2(branchpoint())'
620 $ log 'parents(branchpoint())'
620 $ log 'parents(branchpoint())'
621 0
621 0
622 2
622 2
623 $ log 'removes(a)'
623 $ log 'removes(a)'
624 2
624 2
625 6
625 6
626 $ log 'roots(all())'
626 $ log 'roots(all())'
627 0
627 0
628 $ log 'reverse(2 or 3 or 4 or 5)'
628 $ log 'reverse(2 or 3 or 4 or 5)'
629 5
629 5
630 4
630 4
631 3
631 3
632 2
632 2
633 $ log 'reverse(all())'
633 $ log 'reverse(all())'
634 9
634 9
635 8
635 8
636 7
636 7
637 6
637 6
638 5
638 5
639 4
639 4
640 3
640 3
641 2
641 2
642 1
642 1
643 0
643 0
644 $ log 'reverse(all()) & filelog(b)'
644 $ log 'reverse(all()) & filelog(b)'
645 4
645 4
646 1
646 1
647 $ log 'rev(5)'
647 $ log 'rev(5)'
648 5
648 5
649 $ log 'sort(limit(reverse(all()), 3))'
649 $ log 'sort(limit(reverse(all()), 3))'
650 7
650 7
651 8
651 8
652 9
652 9
653 $ log 'sort(2 or 3 or 4 or 5, date)'
653 $ log 'sort(2 or 3 or 4 or 5, date)'
654 2
654 2
655 3
655 3
656 5
656 5
657 4
657 4
658 $ log 'tagged()'
658 $ log 'tagged()'
659 6
659 6
660 $ log 'tag()'
660 $ log 'tag()'
661 6
661 6
662 $ log 'tag(1.0)'
662 $ log 'tag(1.0)'
663 6
663 6
664 $ log 'tag(tip)'
664 $ log 'tag(tip)'
665 9
665 9
666
666
667 test sort revset
667 test sort revset
668 --------------------------------------------
668 --------------------------------------------
669
669
670 test when adding two unordered revsets
670 test when adding two unordered revsets
671
671
672 $ log 'sort(keyword(issue) or modifies(b))'
672 $ log 'sort(keyword(issue) or modifies(b))'
673 4
673 4
674 6
674 6
675
675
676 test when sorting a reversed collection in the same way it is
676 test when sorting a reversed collection in the same way it is
677
677
678 $ log 'sort(reverse(all()), -rev)'
678 $ log 'sort(reverse(all()), -rev)'
679 9
679 9
680 8
680 8
681 7
681 7
682 6
682 6
683 5
683 5
684 4
684 4
685 3
685 3
686 2
686 2
687 1
687 1
688 0
688 0
689
689
690 test when sorting a reversed collection
690 test when sorting a reversed collection
691
691
692 $ log 'sort(reverse(all()), rev)'
692 $ log 'sort(reverse(all()), rev)'
693 0
693 0
694 1
694 1
695 2
695 2
696 3
696 3
697 4
697 4
698 5
698 5
699 6
699 6
700 7
700 7
701 8
701 8
702 9
702 9
703
703
704
704
705 test sorting two sorted collections in different orders
705 test sorting two sorted collections in different orders
706
706
707 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
707 $ log 'sort(outgoing() or reverse(removes(a)), rev)'
708 2
708 2
709 6
709 6
710 8
710 8
711 9
711 9
712
712
713 test sorting two sorted collections in different orders backwards
713 test sorting two sorted collections in different orders backwards
714
714
715 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
715 $ log 'sort(outgoing() or reverse(removes(a)), -rev)'
716 9
716 9
717 8
717 8
718 6
718 6
719 2
719 2
720
720
721 test subtracting something from an addset
721 test subtracting something from an addset
722
722
723 $ log '(outgoing() or removes(a)) - removes(a)'
723 $ log '(outgoing() or removes(a)) - removes(a)'
724 8
724 8
725 9
725 9
726
726
727 test intersecting something with an addset
727 test intersecting something with an addset
728
728
729 $ log 'parents(outgoing() or removes(a))'
729 $ log 'parents(outgoing() or removes(a))'
730 1
730 1
731 4
731 4
732 5
732 5
733 8
733 8
734
734
735 test that `or` operation combines elements in the right order:
735 test that `or` operation combines elements in the right order:
736
736
737 $ log '3:4 or 2:5'
737 $ log '3:4 or 2:5'
738 3
738 3
739 4
739 4
740 2
740 2
741 5
741 5
742 $ log '3:4 or 5:2'
742 $ log '3:4 or 5:2'
743 3
743 3
744 4
744 4
745 5
745 5
746 2
746 2
747 $ log 'sort(3:4 or 2:5)'
747 $ log 'sort(3:4 or 2:5)'
748 2
748 2
749 3
749 3
750 4
750 4
751 5
751 5
752 $ log 'sort(3:4 or 5:2)'
752 $ log 'sort(3:4 or 5:2)'
753 2
753 2
754 3
754 3
755 4
755 4
756 5
756 5
757
757
758 check that conversion to only works
758 check that conversion to only works
759 $ try --optimize '::3 - ::1'
759 $ try --optimize '::3 - ::1'
760 (minus
760 (minus
761 (dagrangepre
761 (dagrangepre
762 ('symbol', '3'))
762 ('symbol', '3'))
763 (dagrangepre
763 (dagrangepre
764 ('symbol', '1')))
764 ('symbol', '1')))
765 * optimized:
765 * optimized:
766 (func
766 (func
767 ('symbol', 'only')
767 ('symbol', 'only')
768 (list
768 (list
769 ('symbol', '3')
769 ('symbol', '3')
770 ('symbol', '1')))
770 ('symbol', '1')))
771 * set:
771 * set:
772 <baseset+ [3]>
772 <baseset+ [3]>
773 3
773 3
774 $ try --optimize 'ancestors(1) - ancestors(3)'
774 $ try --optimize 'ancestors(1) - ancestors(3)'
775 (minus
775 (minus
776 (func
776 (func
777 ('symbol', 'ancestors')
777 ('symbol', 'ancestors')
778 ('symbol', '1'))
778 ('symbol', '1'))
779 (func
779 (func
780 ('symbol', 'ancestors')
780 ('symbol', 'ancestors')
781 ('symbol', '3')))
781 ('symbol', '3')))
782 * optimized:
782 * optimized:
783 (func
783 (func
784 ('symbol', 'only')
784 ('symbol', 'only')
785 (list
785 (list
786 ('symbol', '1')
786 ('symbol', '1')
787 ('symbol', '3')))
787 ('symbol', '3')))
788 * set:
788 * set:
789 <baseset+ []>
789 <baseset+ []>
790 $ try --optimize 'not ::2 and ::6'
790 $ try --optimize 'not ::2 and ::6'
791 (and
791 (and
792 (not
792 (not
793 (dagrangepre
793 (dagrangepre
794 ('symbol', '2')))
794 ('symbol', '2')))
795 (dagrangepre
795 (dagrangepre
796 ('symbol', '6')))
796 ('symbol', '6')))
797 * optimized:
797 * optimized:
798 (func
798 (func
799 ('symbol', 'only')
799 ('symbol', 'only')
800 (list
800 (list
801 ('symbol', '6')
801 ('symbol', '6')
802 ('symbol', '2')))
802 ('symbol', '2')))
803 * set:
803 * set:
804 <baseset+ [3, 4, 5, 6]>
804 <baseset+ [3, 4, 5, 6]>
805 3
805 3
806 4
806 4
807 5
807 5
808 6
808 6
809 $ try --optimize 'ancestors(6) and not ancestors(4)'
809 $ try --optimize 'ancestors(6) and not ancestors(4)'
810 (and
810 (and
811 (func
811 (func
812 ('symbol', 'ancestors')
812 ('symbol', 'ancestors')
813 ('symbol', '6'))
813 ('symbol', '6'))
814 (not
814 (not
815 (func
815 (func
816 ('symbol', 'ancestors')
816 ('symbol', 'ancestors')
817 ('symbol', '4'))))
817 ('symbol', '4'))))
818 * optimized:
818 * optimized:
819 (func
819 (func
820 ('symbol', 'only')
820 ('symbol', 'only')
821 (list
821 (list
822 ('symbol', '6')
822 ('symbol', '6')
823 ('symbol', '4')))
823 ('symbol', '4')))
824 * set:
824 * set:
825 <baseset+ [3, 5, 6]>
825 <baseset+ [3, 5, 6]>
826 3
826 3
827 5
827 5
828 6
828 6
829
829
830 we can use patterns when searching for tags
830 we can use patterns when searching for tags
831
831
832 $ log 'tag("1..*")'
832 $ log 'tag("1..*")'
833 abort: tag '1..*' does not exist!
833 abort: tag '1..*' does not exist!
834 [255]
834 [255]
835 $ log 'tag("re:1..*")'
835 $ log 'tag("re:1..*")'
836 6
836 6
837 $ log 'tag("re:[0-9].[0-9]")'
837 $ log 'tag("re:[0-9].[0-9]")'
838 6
838 6
839 $ log 'tag("literal:1.0")'
839 $ log 'tag("literal:1.0")'
840 6
840 6
841 $ log 'tag("re:0..*")'
841 $ log 'tag("re:0..*")'
842
842
843 $ log 'tag(unknown)'
843 $ log 'tag(unknown)'
844 abort: tag 'unknown' does not exist!
844 abort: tag 'unknown' does not exist!
845 [255]
845 [255]
846 $ log 'tag("re:unknown")'
846 $ log 'tag("re:unknown")'
847 $ log 'present(tag("unknown"))'
847 $ log 'present(tag("unknown"))'
848 $ log 'present(tag("re:unknown"))'
848 $ log 'present(tag("re:unknown"))'
849 $ log 'branch(unknown)'
849 $ log 'branch(unknown)'
850 abort: unknown revision 'unknown'!
850 abort: unknown revision 'unknown'!
851 [255]
851 [255]
852 $ log 'branch("re:unknown")'
852 $ log 'branch("re:unknown")'
853 $ log 'present(branch("unknown"))'
853 $ log 'present(branch("unknown"))'
854 $ log 'present(branch("re:unknown"))'
854 $ log 'present(branch("re:unknown"))'
855 $ log 'user(bob)'
855 $ log 'user(bob)'
856 2
856 2
857
857
858 $ log '4::8'
858 $ log '4::8'
859 4
859 4
860 8
860 8
861 $ log '4:8'
861 $ log '4:8'
862 4
862 4
863 5
863 5
864 6
864 6
865 7
865 7
866 8
866 8
867
867
868 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
868 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
869 4
869 4
870 2
870 2
871 5
871 5
872
872
873 $ log 'not 0 and 0:2'
873 $ log 'not 0 and 0:2'
874 1
874 1
875 2
875 2
876 $ log 'not 1 and 0:2'
876 $ log 'not 1 and 0:2'
877 0
877 0
878 2
878 2
879 $ log 'not 2 and 0:2'
879 $ log 'not 2 and 0:2'
880 0
880 0
881 1
881 1
882 $ log '(1 and 2)::'
882 $ log '(1 and 2)::'
883 $ log '(1 and 2):'
883 $ log '(1 and 2):'
884 $ log '(1 and 2):3'
884 $ log '(1 and 2):3'
885 $ log 'sort(head(), -rev)'
885 $ log 'sort(head(), -rev)'
886 9
886 9
887 7
887 7
888 6
888 6
889 5
889 5
890 4
890 4
891 3
891 3
892 2
892 2
893 1
893 1
894 0
894 0
895 $ log '4::8 - 8'
895 $ log '4::8 - 8'
896 4
896 4
897 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
897 $ log 'matching(1 or 2 or 3) and (2 or 3 or 1)'
898 2
898 2
899 3
899 3
900 1
900 1
901
901
902 $ log 'named("unknown")'
902 $ log 'named("unknown")'
903 abort: namespace 'unknown' does not exist!
903 abort: namespace 'unknown' does not exist!
904 [255]
904 [255]
905 $ log 'named("re:unknown")'
905 $ log 'named("re:unknown")'
906 abort: no namespace exists that match 'unknown'!
906 abort: no namespace exists that match 'unknown'!
907 [255]
907 [255]
908 $ log 'present(named("unknown"))'
908 $ log 'present(named("unknown"))'
909 $ log 'present(named("re:unknown"))'
909 $ log 'present(named("re:unknown"))'
910
910
911 $ log 'tag()'
911 $ log 'tag()'
912 6
912 6
913 $ log 'named("tags")'
913 $ log 'named("tags")'
914 6
914 6
915
915
916 issue2437
916 issue2437
917
917
918 $ log '3 and p1(5)'
918 $ log '3 and p1(5)'
919 3
919 3
920 $ log '4 and p2(6)'
920 $ log '4 and p2(6)'
921 4
921 4
922 $ log '1 and parents(:2)'
922 $ log '1 and parents(:2)'
923 1
923 1
924 $ log '2 and children(1:)'
924 $ log '2 and children(1:)'
925 2
925 2
926 $ log 'roots(all()) or roots(all())'
926 $ log 'roots(all()) or roots(all())'
927 0
927 0
928 $ hg debugrevspec 'roots(all()) or roots(all())'
928 $ hg debugrevspec 'roots(all()) or roots(all())'
929 0
929 0
930 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
930 $ log 'heads(branch(Γ©)) or heads(branch(Γ©))'
931 9
931 9
932 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
932 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(Γ©)))'
933 4
933 4
934
934
935 issue2654: report a parse error if the revset was not completely parsed
935 issue2654: report a parse error if the revset was not completely parsed
936
936
937 $ log '1 OR 2'
937 $ log '1 OR 2'
938 hg: parse error at 2: invalid token
938 hg: parse error at 2: invalid token
939 [255]
939 [255]
940
940
941 or operator should preserve ordering:
941 or operator should preserve ordering:
942 $ log 'reverse(2::4) or tip'
942 $ log 'reverse(2::4) or tip'
943 4
943 4
944 2
944 2
945 9
945 9
946
946
947 parentrevspec
947 parentrevspec
948
948
949 $ log 'merge()^0'
949 $ log 'merge()^0'
950 6
950 6
951 $ log 'merge()^'
951 $ log 'merge()^'
952 5
952 5
953 $ log 'merge()^1'
953 $ log 'merge()^1'
954 5
954 5
955 $ log 'merge()^2'
955 $ log 'merge()^2'
956 4
956 4
957 $ log 'merge()^^'
957 $ log 'merge()^^'
958 3
958 3
959 $ log 'merge()^1^'
959 $ log 'merge()^1^'
960 3
960 3
961 $ log 'merge()^^^'
961 $ log 'merge()^^^'
962 1
962 1
963
963
964 $ log 'merge()~0'
964 $ log 'merge()~0'
965 6
965 6
966 $ log 'merge()~1'
966 $ log 'merge()~1'
967 5
967 5
968 $ log 'merge()~2'
968 $ log 'merge()~2'
969 3
969 3
970 $ log 'merge()~2^1'
970 $ log 'merge()~2^1'
971 1
971 1
972 $ log 'merge()~3'
972 $ log 'merge()~3'
973 1
973 1
974
974
975 $ log '(-3:tip)^'
975 $ log '(-3:tip)^'
976 4
976 4
977 6
977 6
978 8
978 8
979
979
980 $ log 'tip^foo'
980 $ log 'tip^foo'
981 hg: parse error: ^ expects a number 0, 1, or 2
981 hg: parse error: ^ expects a number 0, 1, or 2
982 [255]
982 [255]
983
983
984 Bogus function gets suggestions
984 Bogus function gets suggestions
985 $ log 'add()'
985 $ log 'add()'
986 hg: parse error: unknown identifier: add
986 hg: parse error: unknown identifier: add
987 (did you mean 'adds'?)
987 (did you mean 'adds'?)
988 [255]
988 [255]
989 $ log 'added()'
989 $ log 'added()'
990 hg: parse error: unknown identifier: added
990 hg: parse error: unknown identifier: added
991 (did you mean 'adds'?)
991 (did you mean 'adds'?)
992 [255]
992 [255]
993 $ log 'remo()'
993 $ log 'remo()'
994 hg: parse error: unknown identifier: remo
994 hg: parse error: unknown identifier: remo
995 (did you mean one of remote, removes?)
995 (did you mean one of remote, removes?)
996 [255]
996 [255]
997 $ log 'babar()'
997 $ log 'babar()'
998 hg: parse error: unknown identifier: babar
998 hg: parse error: unknown identifier: babar
999 [255]
999 [255]
1000
1000
1001 multiple revspecs
1001 multiple revspecs
1002
1002
1003 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1003 $ hg log -r 'tip~1:tip' -r 'tip~2:tip~1' --template '{rev}\n'
1004 8
1004 8
1005 9
1005 9
1006 4
1006 4
1007 5
1007 5
1008 6
1008 6
1009 7
1009 7
1010
1010
1011 test usage in revpair (with "+")
1011 test usage in revpair (with "+")
1012
1012
1013 (real pair)
1013 (real pair)
1014
1014
1015 $ hg diff -r 'tip^^' -r 'tip'
1015 $ hg diff -r 'tip^^' -r 'tip'
1016 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1016 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1017 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1017 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1018 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1018 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1019 @@ -0,0 +1,1 @@
1019 @@ -0,0 +1,1 @@
1020 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1020 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1021 $ hg diff -r 'tip^^::tip'
1021 $ hg diff -r 'tip^^::tip'
1022 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1022 diff -r 2326846efdab -r 24286f4ae135 .hgtags
1023 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1023 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1024 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1024 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
1025 @@ -0,0 +1,1 @@
1025 @@ -0,0 +1,1 @@
1026 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1026 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1027
1027
1028 (single rev)
1028 (single rev)
1029
1029
1030 $ hg diff -r 'tip^' -r 'tip^'
1030 $ hg diff -r 'tip^' -r 'tip^'
1031 $ hg diff -r 'tip^::tip^ or tip^'
1031 $ hg diff -r 'tip^::tip^ or tip^'
1032
1032
1033 (single rev that does not looks like a range)
1033 (single rev that does not looks like a range)
1034
1034
1035 $ hg diff -r 'tip^ or tip^'
1035 $ hg diff -r 'tip^ or tip^'
1036 diff -r d5d0dcbdc4d9 .hgtags
1036 diff -r d5d0dcbdc4d9 .hgtags
1037 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1037 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1038 +++ b/.hgtags * (glob)
1038 +++ b/.hgtags * (glob)
1039 @@ -0,0 +1,1 @@
1039 @@ -0,0 +1,1 @@
1040 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1040 +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
1041
1041
1042 (no rev)
1042 (no rev)
1043
1043
1044 $ hg diff -r 'author("babar") or author("celeste")'
1044 $ hg diff -r 'author("babar") or author("celeste")'
1045 abort: empty revision range
1045 abort: empty revision range
1046 [255]
1046 [255]
1047
1047
1048 aliases:
1048 aliases:
1049
1049
1050 $ echo '[revsetalias]' >> .hg/hgrc
1050 $ echo '[revsetalias]' >> .hg/hgrc
1051 $ echo 'm = merge()' >> .hg/hgrc
1051 $ echo 'm = merge()' >> .hg/hgrc
1052 (revset aliases can override builtin revsets)
1053 $ echo 'p2($1) = p1($1)' >> .hg/hgrc
1052 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1054 $ echo 'sincem = descendants(m)' >> .hg/hgrc
1053 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1055 $ echo 'd($1) = reverse(sort($1, date))' >> .hg/hgrc
1054 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1056 $ echo 'rs(ARG1, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1055 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1057 $ echo 'rs4(ARG1, ARGA, ARGB, ARG2) = reverse(sort(ARG1, ARG2))' >> .hg/hgrc
1056
1058
1057 $ try m
1059 $ try m
1058 ('symbol', 'm')
1060 ('symbol', 'm')
1059 (func
1061 (func
1060 ('symbol', 'merge')
1062 ('symbol', 'merge')
1061 None)
1063 None)
1062 * set:
1064 * set:
1063 <filteredset
1065 <filteredset
1064 <fullreposet+ 0:9>>
1066 <fullreposet+ 0:9>>
1065 6
1067 6
1066
1068
1069 $ HGPLAIN=1 try m
1070 ('symbol', 'm')
1071 abort: unknown revision 'm'!
1072 [255]
1073
1074 $ HGPLAIN=1 HGPLAINEXCEPT=revsetalias try m
1075 ('symbol', 'm')
1076 (func
1077 ('symbol', 'merge')
1078 None)
1079 * set:
1080 <filteredset
1081 <fullreposet+ 0:9>>
1082 6
1083
1084 (for some reason HGPLAIN and HGPLAINEXCEPT can carry forward)
1085
1086 $ unset HGPLAIN
1087 $ unset HGPLAINEXCEPT
1088
1089 $ try 'p2(.)'
1090 (func
1091 ('symbol', 'p2')
1092 ('symbol', '.'))
1093 (func
1094 ('symbol', 'p1')
1095 ('symbol', '.'))
1096 * set:
1097 <baseset+ [8]>
1098 8
1099
1100 $ HGPLAIN=1 try 'p2(.)'
1101 (func
1102 ('symbol', 'p2')
1103 ('symbol', '.'))
1104 * set:
1105 <baseset+ []>
1106
1107 $ HGPLAIN=1 HGPLAINEXCEPT=revsetalias try 'p2(.)'
1108 (func
1109 ('symbol', 'p2')
1110 ('symbol', '.'))
1111 (func
1112 ('symbol', 'p1')
1113 ('symbol', '.'))
1114 * set:
1115 <baseset+ [8]>
1116 8
1117
1118 $ unset HGPLAIN
1119 $ unset HGPLAINEXCEPT
1120
1067 test alias recursion
1121 test alias recursion
1068
1122
1069 $ try sincem
1123 $ try sincem
1070 ('symbol', 'sincem')
1124 ('symbol', 'sincem')
1071 (func
1125 (func
1072 ('symbol', 'descendants')
1126 ('symbol', 'descendants')
1073 (func
1127 (func
1074 ('symbol', 'merge')
1128 ('symbol', 'merge')
1075 None))
1129 None))
1076 * set:
1130 * set:
1077 <addset+
1131 <addset+
1078 <filteredset
1132 <filteredset
1079 <fullreposet+ 0:9>>,
1133 <fullreposet+ 0:9>>,
1080 <generatorset+>>
1134 <generatorset+>>
1081 6
1135 6
1082 7
1136 7
1083
1137
1084 test infinite recursion
1138 test infinite recursion
1085
1139
1086 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1140 $ echo 'recurse1 = recurse2' >> .hg/hgrc
1087 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1141 $ echo 'recurse2 = recurse1' >> .hg/hgrc
1088 $ try recurse1
1142 $ try recurse1
1089 ('symbol', 'recurse1')
1143 ('symbol', 'recurse1')
1090 hg: parse error: infinite expansion of revset alias "recurse1" detected
1144 hg: parse error: infinite expansion of revset alias "recurse1" detected
1091 [255]
1145 [255]
1092
1146
1093 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1147 $ echo 'level1($1, $2) = $1 or $2' >> .hg/hgrc
1094 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1148 $ echo 'level2($1, $2) = level1($2, $1)' >> .hg/hgrc
1095 $ try "level2(level1(1, 2), 3)"
1149 $ try "level2(level1(1, 2), 3)"
1096 (func
1150 (func
1097 ('symbol', 'level2')
1151 ('symbol', 'level2')
1098 (list
1152 (list
1099 (func
1153 (func
1100 ('symbol', 'level1')
1154 ('symbol', 'level1')
1101 (list
1155 (list
1102 ('symbol', '1')
1156 ('symbol', '1')
1103 ('symbol', '2')))
1157 ('symbol', '2')))
1104 ('symbol', '3')))
1158 ('symbol', '3')))
1105 (or
1159 (or
1106 ('symbol', '3')
1160 ('symbol', '3')
1107 (or
1161 (or
1108 ('symbol', '1')
1162 ('symbol', '1')
1109 ('symbol', '2')))
1163 ('symbol', '2')))
1110 * set:
1164 * set:
1111 <addset
1165 <addset
1112 <baseset [3]>,
1166 <baseset [3]>,
1113 <addset
1167 <addset
1114 <baseset [1]>,
1168 <baseset [1]>,
1115 <baseset [2]>>>
1169 <baseset [2]>>>
1116 3
1170 3
1117 1
1171 1
1118 2
1172 2
1119
1173
1120 test nesting and variable passing
1174 test nesting and variable passing
1121
1175
1122 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1176 $ echo 'nested($1) = nested2($1)' >> .hg/hgrc
1123 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1177 $ echo 'nested2($1) = nested3($1)' >> .hg/hgrc
1124 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1178 $ echo 'nested3($1) = max($1)' >> .hg/hgrc
1125 $ try 'nested(2:5)'
1179 $ try 'nested(2:5)'
1126 (func
1180 (func
1127 ('symbol', 'nested')
1181 ('symbol', 'nested')
1128 (range
1182 (range
1129 ('symbol', '2')
1183 ('symbol', '2')
1130 ('symbol', '5')))
1184 ('symbol', '5')))
1131 (func
1185 (func
1132 ('symbol', 'max')
1186 ('symbol', 'max')
1133 (range
1187 (range
1134 ('symbol', '2')
1188 ('symbol', '2')
1135 ('symbol', '5')))
1189 ('symbol', '5')))
1136 * set:
1190 * set:
1137 <baseset [5]>
1191 <baseset [5]>
1138 5
1192 5
1139
1193
1140 test variable isolation, variable placeholders are rewritten as string
1194 test variable isolation, variable placeholders are rewritten as string
1141 then parsed and matched again as string. Check they do not leak too
1195 then parsed and matched again as string. Check they do not leak too
1142 far away.
1196 far away.
1143
1197
1144 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1198 $ echo 'injectparamasstring = max("$1")' >> .hg/hgrc
1145 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1199 $ echo 'callinjection($1) = descendants(injectparamasstring)' >> .hg/hgrc
1146 $ try 'callinjection(2:5)'
1200 $ try 'callinjection(2:5)'
1147 (func
1201 (func
1148 ('symbol', 'callinjection')
1202 ('symbol', 'callinjection')
1149 (range
1203 (range
1150 ('symbol', '2')
1204 ('symbol', '2')
1151 ('symbol', '5')))
1205 ('symbol', '5')))
1152 (func
1206 (func
1153 ('symbol', 'descendants')
1207 ('symbol', 'descendants')
1154 (func
1208 (func
1155 ('symbol', 'max')
1209 ('symbol', 'max')
1156 ('string', '$1')))
1210 ('string', '$1')))
1157 abort: unknown revision '$1'!
1211 abort: unknown revision '$1'!
1158 [255]
1212 [255]
1159
1213
1160 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1214 $ echo 'injectparamasstring2 = max(_aliasarg("$1"))' >> .hg/hgrc
1161 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1215 $ echo 'callinjection2($1) = descendants(injectparamasstring2)' >> .hg/hgrc
1162 $ try 'callinjection2(2:5)'
1216 $ try 'callinjection2(2:5)'
1163 (func
1217 (func
1164 ('symbol', 'callinjection2')
1218 ('symbol', 'callinjection2')
1165 (range
1219 (range
1166 ('symbol', '2')
1220 ('symbol', '2')
1167 ('symbol', '5')))
1221 ('symbol', '5')))
1168 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1222 abort: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1169 [255]
1223 [255]
1170 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1224 $ hg debugrevspec --debug --config revsetalias.anotherbadone='branch(' "tip"
1171 ('symbol', 'tip')
1225 ('symbol', 'tip')
1172 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1226 warning: failed to parse the definition of revset alias "anotherbadone": at 7: not a prefix: end
1173 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1227 warning: failed to parse the definition of revset alias "injectparamasstring2": unknown identifier: _aliasarg
1174 * set:
1228 * set:
1175 <baseset [9]>
1229 <baseset [9]>
1176 9
1230 9
1177 >>> data = file('.hg/hgrc', 'rb').read()
1231 >>> data = file('.hg/hgrc', 'rb').read()
1178 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1232 >>> file('.hg/hgrc', 'wb').write(data.replace('_aliasarg', ''))
1179
1233
1180 $ try 'tip'
1234 $ try 'tip'
1181 ('symbol', 'tip')
1235 ('symbol', 'tip')
1182 * set:
1236 * set:
1183 <baseset [9]>
1237 <baseset [9]>
1184 9
1238 9
1185
1239
1186 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1240 $ hg debugrevspec --debug --config revsetalias.'bad name'='tip' "tip"
1187 ('symbol', 'tip')
1241 ('symbol', 'tip')
1188 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1242 warning: failed to parse the declaration of revset alias "bad name": at 4: invalid token
1189 * set:
1243 * set:
1190 <baseset [9]>
1244 <baseset [9]>
1191 9
1245 9
1192 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1246 $ echo 'strictreplacing($1, $10) = $10 or desc("$1")' >> .hg/hgrc
1193 $ try 'strictreplacing("foo", tip)'
1247 $ try 'strictreplacing("foo", tip)'
1194 (func
1248 (func
1195 ('symbol', 'strictreplacing')
1249 ('symbol', 'strictreplacing')
1196 (list
1250 (list
1197 ('string', 'foo')
1251 ('string', 'foo')
1198 ('symbol', 'tip')))
1252 ('symbol', 'tip')))
1199 (or
1253 (or
1200 ('symbol', 'tip')
1254 ('symbol', 'tip')
1201 (func
1255 (func
1202 ('symbol', 'desc')
1256 ('symbol', 'desc')
1203 ('string', '$1')))
1257 ('string', '$1')))
1204 * set:
1258 * set:
1205 <addset
1259 <addset
1206 <baseset [9]>,
1260 <baseset [9]>,
1207 <filteredset
1261 <filteredset
1208 <filteredset
1262 <filteredset
1209 <fullreposet+ 0:9>>>>
1263 <fullreposet+ 0:9>>>>
1210 9
1264 9
1211
1265
1212 $ try 'd(2:5)'
1266 $ try 'd(2:5)'
1213 (func
1267 (func
1214 ('symbol', 'd')
1268 ('symbol', 'd')
1215 (range
1269 (range
1216 ('symbol', '2')
1270 ('symbol', '2')
1217 ('symbol', '5')))
1271 ('symbol', '5')))
1218 (func
1272 (func
1219 ('symbol', 'reverse')
1273 ('symbol', 'reverse')
1220 (func
1274 (func
1221 ('symbol', 'sort')
1275 ('symbol', 'sort')
1222 (list
1276 (list
1223 (range
1277 (range
1224 ('symbol', '2')
1278 ('symbol', '2')
1225 ('symbol', '5'))
1279 ('symbol', '5'))
1226 ('symbol', 'date'))))
1280 ('symbol', 'date'))))
1227 * set:
1281 * set:
1228 <baseset [4, 5, 3, 2]>
1282 <baseset [4, 5, 3, 2]>
1229 4
1283 4
1230 5
1284 5
1231 3
1285 3
1232 2
1286 2
1233 $ try 'rs(2 or 3, date)'
1287 $ try 'rs(2 or 3, date)'
1234 (func
1288 (func
1235 ('symbol', 'rs')
1289 ('symbol', 'rs')
1236 (list
1290 (list
1237 (or
1291 (or
1238 ('symbol', '2')
1292 ('symbol', '2')
1239 ('symbol', '3'))
1293 ('symbol', '3'))
1240 ('symbol', 'date')))
1294 ('symbol', 'date')))
1241 (func
1295 (func
1242 ('symbol', 'reverse')
1296 ('symbol', 'reverse')
1243 (func
1297 (func
1244 ('symbol', 'sort')
1298 ('symbol', 'sort')
1245 (list
1299 (list
1246 (or
1300 (or
1247 ('symbol', '2')
1301 ('symbol', '2')
1248 ('symbol', '3'))
1302 ('symbol', '3'))
1249 ('symbol', 'date'))))
1303 ('symbol', 'date'))))
1250 * set:
1304 * set:
1251 <baseset [3, 2]>
1305 <baseset [3, 2]>
1252 3
1306 3
1253 2
1307 2
1254 $ try 'rs()'
1308 $ try 'rs()'
1255 (func
1309 (func
1256 ('symbol', 'rs')
1310 ('symbol', 'rs')
1257 None)
1311 None)
1258 hg: parse error: invalid number of arguments: 0
1312 hg: parse error: invalid number of arguments: 0
1259 [255]
1313 [255]
1260 $ try 'rs(2)'
1314 $ try 'rs(2)'
1261 (func
1315 (func
1262 ('symbol', 'rs')
1316 ('symbol', 'rs')
1263 ('symbol', '2'))
1317 ('symbol', '2'))
1264 hg: parse error: invalid number of arguments: 1
1318 hg: parse error: invalid number of arguments: 1
1265 [255]
1319 [255]
1266 $ try 'rs(2, data, 7)'
1320 $ try 'rs(2, data, 7)'
1267 (func
1321 (func
1268 ('symbol', 'rs')
1322 ('symbol', 'rs')
1269 (list
1323 (list
1270 (list
1324 (list
1271 ('symbol', '2')
1325 ('symbol', '2')
1272 ('symbol', 'data'))
1326 ('symbol', 'data'))
1273 ('symbol', '7')))
1327 ('symbol', '7')))
1274 hg: parse error: invalid number of arguments: 3
1328 hg: parse error: invalid number of arguments: 3
1275 [255]
1329 [255]
1276 $ try 'rs4(2 or 3, x, x, date)'
1330 $ try 'rs4(2 or 3, x, x, date)'
1277 (func
1331 (func
1278 ('symbol', 'rs4')
1332 ('symbol', 'rs4')
1279 (list
1333 (list
1280 (list
1334 (list
1281 (list
1335 (list
1282 (or
1336 (or
1283 ('symbol', '2')
1337 ('symbol', '2')
1284 ('symbol', '3'))
1338 ('symbol', '3'))
1285 ('symbol', 'x'))
1339 ('symbol', 'x'))
1286 ('symbol', 'x'))
1340 ('symbol', 'x'))
1287 ('symbol', 'date')))
1341 ('symbol', 'date')))
1288 (func
1342 (func
1289 ('symbol', 'reverse')
1343 ('symbol', 'reverse')
1290 (func
1344 (func
1291 ('symbol', 'sort')
1345 ('symbol', 'sort')
1292 (list
1346 (list
1293 (or
1347 (or
1294 ('symbol', '2')
1348 ('symbol', '2')
1295 ('symbol', '3'))
1349 ('symbol', '3'))
1296 ('symbol', 'date'))))
1350 ('symbol', 'date'))))
1297 * set:
1351 * set:
1298 <baseset [3, 2]>
1352 <baseset [3, 2]>
1299 3
1353 3
1300 2
1354 2
1301
1355
1302 issue4553: check that revset aliases override existing hash prefix
1356 issue4553: check that revset aliases override existing hash prefix
1303
1357
1304 $ hg log -qr e
1358 $ hg log -qr e
1305 6:e0cc66ef77e8
1359 6:e0cc66ef77e8
1306
1360
1307 $ hg log -qr e --config revsetalias.e="all()"
1361 $ hg log -qr e --config revsetalias.e="all()"
1308 0:2785f51eece5
1362 0:2785f51eece5
1309 1:d75937da8da0
1363 1:d75937da8da0
1310 2:5ed5505e9f1c
1364 2:5ed5505e9f1c
1311 3:8528aa5637f2
1365 3:8528aa5637f2
1312 4:2326846efdab
1366 4:2326846efdab
1313 5:904fa392b941
1367 5:904fa392b941
1314 6:e0cc66ef77e8
1368 6:e0cc66ef77e8
1315 7:013af1973af4
1369 7:013af1973af4
1316 8:d5d0dcbdc4d9
1370 8:d5d0dcbdc4d9
1317 9:24286f4ae135
1371 9:24286f4ae135
1318
1372
1319 $ hg log -qr e: --config revsetalias.e="0"
1373 $ hg log -qr e: --config revsetalias.e="0"
1320 0:2785f51eece5
1374 0:2785f51eece5
1321 1:d75937da8da0
1375 1:d75937da8da0
1322 2:5ed5505e9f1c
1376 2:5ed5505e9f1c
1323 3:8528aa5637f2
1377 3:8528aa5637f2
1324 4:2326846efdab
1378 4:2326846efdab
1325 5:904fa392b941
1379 5:904fa392b941
1326 6:e0cc66ef77e8
1380 6:e0cc66ef77e8
1327 7:013af1973af4
1381 7:013af1973af4
1328 8:d5d0dcbdc4d9
1382 8:d5d0dcbdc4d9
1329 9:24286f4ae135
1383 9:24286f4ae135
1330
1384
1331 $ hg log -qr :e --config revsetalias.e="9"
1385 $ hg log -qr :e --config revsetalias.e="9"
1332 0:2785f51eece5
1386 0:2785f51eece5
1333 1:d75937da8da0
1387 1:d75937da8da0
1334 2:5ed5505e9f1c
1388 2:5ed5505e9f1c
1335 3:8528aa5637f2
1389 3:8528aa5637f2
1336 4:2326846efdab
1390 4:2326846efdab
1337 5:904fa392b941
1391 5:904fa392b941
1338 6:e0cc66ef77e8
1392 6:e0cc66ef77e8
1339 7:013af1973af4
1393 7:013af1973af4
1340 8:d5d0dcbdc4d9
1394 8:d5d0dcbdc4d9
1341 9:24286f4ae135
1395 9:24286f4ae135
1342
1396
1343 $ hg log -qr e:
1397 $ hg log -qr e:
1344 6:e0cc66ef77e8
1398 6:e0cc66ef77e8
1345 7:013af1973af4
1399 7:013af1973af4
1346 8:d5d0dcbdc4d9
1400 8:d5d0dcbdc4d9
1347 9:24286f4ae135
1401 9:24286f4ae135
1348
1402
1349 $ hg log -qr :e
1403 $ hg log -qr :e
1350 0:2785f51eece5
1404 0:2785f51eece5
1351 1:d75937da8da0
1405 1:d75937da8da0
1352 2:5ed5505e9f1c
1406 2:5ed5505e9f1c
1353 3:8528aa5637f2
1407 3:8528aa5637f2
1354 4:2326846efdab
1408 4:2326846efdab
1355 5:904fa392b941
1409 5:904fa392b941
1356 6:e0cc66ef77e8
1410 6:e0cc66ef77e8
1357
1411
1358 issue2549 - correct optimizations
1412 issue2549 - correct optimizations
1359
1413
1360 $ log 'limit(1 or 2 or 3, 2) and not 2'
1414 $ log 'limit(1 or 2 or 3, 2) and not 2'
1361 1
1415 1
1362 $ log 'max(1 or 2) and not 2'
1416 $ log 'max(1 or 2) and not 2'
1363 $ log 'min(1 or 2) and not 1'
1417 $ log 'min(1 or 2) and not 1'
1364 $ log 'last(1 or 2, 1) and not 2'
1418 $ log 'last(1 or 2, 1) and not 2'
1365
1419
1366 issue4289 - ordering of built-ins
1420 issue4289 - ordering of built-ins
1367 $ hg log -M -q -r 3:2
1421 $ hg log -M -q -r 3:2
1368 3:8528aa5637f2
1422 3:8528aa5637f2
1369 2:5ed5505e9f1c
1423 2:5ed5505e9f1c
1370
1424
1371 test revsets started with 40-chars hash (issue3669)
1425 test revsets started with 40-chars hash (issue3669)
1372
1426
1373 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1427 $ ISSUE3669_TIP=`hg tip --template '{node}'`
1374 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1428 $ hg log -r "${ISSUE3669_TIP}" --template '{rev}\n'
1375 9
1429 9
1376 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1430 $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
1377 8
1431 8
1378
1432
1379 test or-ed indirect predicates (issue3775)
1433 test or-ed indirect predicates (issue3775)
1380
1434
1381 $ log '6 or 6^1' | sort
1435 $ log '6 or 6^1' | sort
1382 5
1436 5
1383 6
1437 6
1384 $ log '6^1 or 6' | sort
1438 $ log '6^1 or 6' | sort
1385 5
1439 5
1386 6
1440 6
1387 $ log '4 or 4~1' | sort
1441 $ log '4 or 4~1' | sort
1388 2
1442 2
1389 4
1443 4
1390 $ log '4~1 or 4' | sort
1444 $ log '4~1 or 4' | sort
1391 2
1445 2
1392 4
1446 4
1393 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1447 $ log '(0 or 2):(4 or 6) or 0 or 6' | sort
1394 0
1448 0
1395 1
1449 1
1396 2
1450 2
1397 3
1451 3
1398 4
1452 4
1399 5
1453 5
1400 6
1454 6
1401 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1455 $ log '0 or 6 or (0 or 2):(4 or 6)' | sort
1402 0
1456 0
1403 1
1457 1
1404 2
1458 2
1405 3
1459 3
1406 4
1460 4
1407 5
1461 5
1408 6
1462 6
1409
1463
1410 tests for 'remote()' predicate:
1464 tests for 'remote()' predicate:
1411 #. (csets in remote) (id) (remote)
1465 #. (csets in remote) (id) (remote)
1412 1. less than local current branch "default"
1466 1. less than local current branch "default"
1413 2. same with local specified "default"
1467 2. same with local specified "default"
1414 3. more than local specified specified
1468 3. more than local specified specified
1415
1469
1416 $ hg clone --quiet -U . ../remote3
1470 $ hg clone --quiet -U . ../remote3
1417 $ cd ../remote3
1471 $ cd ../remote3
1418 $ hg update -q 7
1472 $ hg update -q 7
1419 $ echo r > r
1473 $ echo r > r
1420 $ hg ci -Aqm 10
1474 $ hg ci -Aqm 10
1421 $ log 'remote()'
1475 $ log 'remote()'
1422 7
1476 7
1423 $ log 'remote("a-b-c-")'
1477 $ log 'remote("a-b-c-")'
1424 2
1478 2
1425 $ cd ../repo
1479 $ cd ../repo
1426 $ log 'remote(".a.b.c.", "../remote3")'
1480 $ log 'remote(".a.b.c.", "../remote3")'
1427
1481
1428 tests for concatenation of strings/symbols by "##"
1482 tests for concatenation of strings/symbols by "##"
1429
1483
1430 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1484 $ try "278 ## '5f5' ## 1ee ## 'ce5'"
1431 (_concat
1485 (_concat
1432 (_concat
1486 (_concat
1433 (_concat
1487 (_concat
1434 ('symbol', '278')
1488 ('symbol', '278')
1435 ('string', '5f5'))
1489 ('string', '5f5'))
1436 ('symbol', '1ee'))
1490 ('symbol', '1ee'))
1437 ('string', 'ce5'))
1491 ('string', 'ce5'))
1438 ('string', '2785f51eece5')
1492 ('string', '2785f51eece5')
1439 * set:
1493 * set:
1440 <baseset [0]>
1494 <baseset [0]>
1441 0
1495 0
1442
1496
1443 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1497 $ echo 'cat4($1, $2, $3, $4) = $1 ## $2 ## $3 ## $4' >> .hg/hgrc
1444 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1498 $ try "cat4(278, '5f5', 1ee, 'ce5')"
1445 (func
1499 (func
1446 ('symbol', 'cat4')
1500 ('symbol', 'cat4')
1447 (list
1501 (list
1448 (list
1502 (list
1449 (list
1503 (list
1450 ('symbol', '278')
1504 ('symbol', '278')
1451 ('string', '5f5'))
1505 ('string', '5f5'))
1452 ('symbol', '1ee'))
1506 ('symbol', '1ee'))
1453 ('string', 'ce5')))
1507 ('string', 'ce5')))
1454 (_concat
1508 (_concat
1455 (_concat
1509 (_concat
1456 (_concat
1510 (_concat
1457 ('symbol', '278')
1511 ('symbol', '278')
1458 ('string', '5f5'))
1512 ('string', '5f5'))
1459 ('symbol', '1ee'))
1513 ('symbol', '1ee'))
1460 ('string', 'ce5'))
1514 ('string', 'ce5'))
1461 ('string', '2785f51eece5')
1515 ('string', '2785f51eece5')
1462 * set:
1516 * set:
1463 <baseset [0]>
1517 <baseset [0]>
1464 0
1518 0
1465
1519
1466 (check concatenation in alias nesting)
1520 (check concatenation in alias nesting)
1467
1521
1468 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1522 $ echo 'cat2($1, $2) = $1 ## $2' >> .hg/hgrc
1469 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1523 $ echo 'cat2x2($1, $2, $3, $4) = cat2($1 ## $2, $3 ## $4)' >> .hg/hgrc
1470 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1524 $ log "cat2x2(278, '5f5', 1ee, 'ce5')"
1471 0
1525 0
1472
1526
1473 (check operator priority)
1527 (check operator priority)
1474
1528
1475 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1529 $ echo 'cat2n2($1, $2, $3, $4) = $1 ## $2 or $3 ## $4~2' >> .hg/hgrc
1476 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1530 $ log "cat2n2(2785f5, 1eece5, 24286f, 4ae135)"
1477 0
1531 0
1478 4
1532 4
1479
1533
1480 $ cd ..
1534 $ cd ..
1481
1535
1482 test author/desc/keyword in problematic encoding
1536 test author/desc/keyword in problematic encoding
1483 # unicode: cp932:
1537 # unicode: cp932:
1484 # u30A2 0x83 0x41(= 'A')
1538 # u30A2 0x83 0x41(= 'A')
1485 # u30C2 0x83 0x61(= 'a')
1539 # u30C2 0x83 0x61(= 'a')
1486
1540
1487 $ hg init problematicencoding
1541 $ hg init problematicencoding
1488 $ cd problematicencoding
1542 $ cd problematicencoding
1489
1543
1490 $ python > setup.sh <<EOF
1544 $ python > setup.sh <<EOF
1491 > print u'''
1545 > print u'''
1492 > echo a > text
1546 > echo a > text
1493 > hg add text
1547 > hg add text
1494 > hg --encoding utf-8 commit -u '\u30A2' -m none
1548 > hg --encoding utf-8 commit -u '\u30A2' -m none
1495 > echo b > text
1549 > echo b > text
1496 > hg --encoding utf-8 commit -u '\u30C2' -m none
1550 > hg --encoding utf-8 commit -u '\u30C2' -m none
1497 > echo c > text
1551 > echo c > text
1498 > hg --encoding utf-8 commit -u none -m '\u30A2'
1552 > hg --encoding utf-8 commit -u none -m '\u30A2'
1499 > echo d > text
1553 > echo d > text
1500 > hg --encoding utf-8 commit -u none -m '\u30C2'
1554 > hg --encoding utf-8 commit -u none -m '\u30C2'
1501 > '''.encode('utf-8')
1555 > '''.encode('utf-8')
1502 > EOF
1556 > EOF
1503 $ sh < setup.sh
1557 $ sh < setup.sh
1504
1558
1505 test in problematic encoding
1559 test in problematic encoding
1506 $ python > test.sh <<EOF
1560 $ python > test.sh <<EOF
1507 > print u'''
1561 > print u'''
1508 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1562 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30A2)'
1509 > echo ====
1563 > echo ====
1510 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1564 > hg --encoding cp932 log --template '{rev}\\n' -r 'author(\u30C2)'
1511 > echo ====
1565 > echo ====
1512 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1566 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30A2)'
1513 > echo ====
1567 > echo ====
1514 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1568 > hg --encoding cp932 log --template '{rev}\\n' -r 'desc(\u30C2)'
1515 > echo ====
1569 > echo ====
1516 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1570 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30A2)'
1517 > echo ====
1571 > echo ====
1518 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1572 > hg --encoding cp932 log --template '{rev}\\n' -r 'keyword(\u30C2)'
1519 > '''.encode('cp932')
1573 > '''.encode('cp932')
1520 > EOF
1574 > EOF
1521 $ sh < test.sh
1575 $ sh < test.sh
1522 0
1576 0
1523 ====
1577 ====
1524 1
1578 1
1525 ====
1579 ====
1526 2
1580 2
1527 ====
1581 ====
1528 3
1582 3
1529 ====
1583 ====
1530 0
1584 0
1531 2
1585 2
1532 ====
1586 ====
1533 1
1587 1
1534 3
1588 3
1535
1589
1536 test error message of bad revset
1590 test error message of bad revset
1537 $ hg log -r 'foo\\'
1591 $ hg log -r 'foo\\'
1538 hg: parse error at 3: syntax error in revset 'foo\\'
1592 hg: parse error at 3: syntax error in revset 'foo\\'
1539 [255]
1593 [255]
1540
1594
1541 $ cd ..
1595 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now