##// END OF EJS Templates
ui: remove urllib2 from being imported early...
Kyle Lippincott -
r30945:8b83b626 default
parent child Browse files
Show More
@@ -1,1460 +1,1478
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import contextlib
10 import contextlib
11 import errno
11 import errno
12 import getpass
12 import getpass
13 import inspect
13 import inspect
14 import os
14 import os
15 import re
15 import re
16 import socket
16 import socket
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import traceback
19 import traceback
20
20
21 from .i18n import _
21 from .i18n import _
22 from .node import hex
22 from .node import hex
23
23
24 from . import (
24 from . import (
25 config,
25 config,
26 encoding,
26 encoding,
27 error,
27 error,
28 formatter,
28 formatter,
29 progress,
29 progress,
30 pycompat,
30 pycompat,
31 scmutil,
31 scmutil,
32 util,
32 util,
33 )
33 )
34
34
35 urlreq = util.urlreq
35 urlreq = util.urlreq
36
36
37 samplehgrcs = {
37 samplehgrcs = {
38 'user':
38 'user':
39 """# example user config (see 'hg help config' for more info)
39 """# example user config (see 'hg help config' for more info)
40 [ui]
40 [ui]
41 # name and email, e.g.
41 # name and email, e.g.
42 # username = Jane Doe <jdoe@example.com>
42 # username = Jane Doe <jdoe@example.com>
43 username =
43 username =
44
44
45 [extensions]
45 [extensions]
46 # uncomment these lines to enable some popular extensions
46 # uncomment these lines to enable some popular extensions
47 # (see 'hg help extensions' for more info)
47 # (see 'hg help extensions' for more info)
48 #
48 #
49 # pager =
49 # pager =
50 # color =""",
50 # color =""",
51
51
52 'cloned':
52 'cloned':
53 """# example repository config (see 'hg help config' for more info)
53 """# example repository config (see 'hg help config' for more info)
54 [paths]
54 [paths]
55 default = %s
55 default = %s
56
56
57 # path aliases to other clones of this repo in URLs or filesystem paths
57 # path aliases to other clones of this repo in URLs or filesystem paths
58 # (see 'hg help config.paths' for more info)
58 # (see 'hg help config.paths' for more info)
59 #
59 #
60 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
60 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
61 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
61 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
62 # my-clone = /home/jdoe/jdoes-clone
62 # my-clone = /home/jdoe/jdoes-clone
63
63
64 [ui]
64 [ui]
65 # name and email (local to this repository, optional), e.g.
65 # name and email (local to this repository, optional), e.g.
66 # username = Jane Doe <jdoe@example.com>
66 # username = Jane Doe <jdoe@example.com>
67 """,
67 """,
68
68
69 'local':
69 'local':
70 """# example repository config (see 'hg help config' for more info)
70 """# example repository config (see 'hg help config' for more info)
71 [paths]
71 [paths]
72 # path aliases to other clones of this repo in URLs or filesystem paths
72 # path aliases to other clones of this repo in URLs or filesystem paths
73 # (see 'hg help config.paths' for more info)
73 # (see 'hg help config.paths' for more info)
74 #
74 #
75 # default = http://example.com/hg/example-repo
75 # default = http://example.com/hg/example-repo
76 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
76 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
77 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
77 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
78 # my-clone = /home/jdoe/jdoes-clone
78 # my-clone = /home/jdoe/jdoes-clone
79
79
80 [ui]
80 [ui]
81 # name and email (local to this repository, optional), e.g.
81 # name and email (local to this repository, optional), e.g.
82 # username = Jane Doe <jdoe@example.com>
82 # username = Jane Doe <jdoe@example.com>
83 """,
83 """,
84
84
85 'global':
85 'global':
86 """# example system-wide hg config (see 'hg help config' for more info)
86 """# example system-wide hg config (see 'hg help config' for more info)
87
87
88 [extensions]
88 [extensions]
89 # uncomment these lines to enable some popular extensions
89 # uncomment these lines to enable some popular extensions
90 # (see 'hg help extensions' for more info)
90 # (see 'hg help extensions' for more info)
91 #
91 #
92 # blackbox =
92 # blackbox =
93 # color =
93 # color =
94 # pager =""",
94 # pager =""",
95 }
95 }
96
96
97
98 class httppasswordmgrdbproxy(object):
99 """Delays loading urllib2 until it's needed."""
100 def __init__(self):
101 self._mgr = None
102
103 def _get_mgr(self):
104 if self._mgr is None:
105 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
106 return self._mgr
107
108 def add_password(self, *args, **kwargs):
109 return self._get_mgr().add_password(*args, **kwargs)
110
111 def find_user_password(self, *args, **kwargs):
112 return self._get_mgr().find_user_password(*args, **kwargs)
113
114
97 class ui(object):
115 class ui(object):
98 def __init__(self, src=None):
116 def __init__(self, src=None):
99 """Create a fresh new ui object if no src given
117 """Create a fresh new ui object if no src given
100
118
101 Use uimod.ui.load() to create a ui which knows global and user configs.
119 Use uimod.ui.load() to create a ui which knows global and user configs.
102 In most cases, you should use ui.copy() to create a copy of an existing
120 In most cases, you should use ui.copy() to create a copy of an existing
103 ui object.
121 ui object.
104 """
122 """
105 # _buffers: used for temporary capture of output
123 # _buffers: used for temporary capture of output
106 self._buffers = []
124 self._buffers = []
107 # 3-tuple describing how each buffer in the stack behaves.
125 # 3-tuple describing how each buffer in the stack behaves.
108 # Values are (capture stderr, capture subprocesses, apply labels).
126 # Values are (capture stderr, capture subprocesses, apply labels).
109 self._bufferstates = []
127 self._bufferstates = []
110 # When a buffer is active, defines whether we are expanding labels.
128 # When a buffer is active, defines whether we are expanding labels.
111 # This exists to prevent an extra list lookup.
129 # This exists to prevent an extra list lookup.
112 self._bufferapplylabels = None
130 self._bufferapplylabels = None
113 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
131 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
114 self._reportuntrusted = True
132 self._reportuntrusted = True
115 self._ocfg = config.config() # overlay
133 self._ocfg = config.config() # overlay
116 self._tcfg = config.config() # trusted
134 self._tcfg = config.config() # trusted
117 self._ucfg = config.config() # untrusted
135 self._ucfg = config.config() # untrusted
118 self._trustusers = set()
136 self._trustusers = set()
119 self._trustgroups = set()
137 self._trustgroups = set()
120 self.callhooks = True
138 self.callhooks = True
121 # Insecure server connections requested.
139 # Insecure server connections requested.
122 self.insecureconnections = False
140 self.insecureconnections = False
123
141
124 if src:
142 if src:
125 self.fout = src.fout
143 self.fout = src.fout
126 self.ferr = src.ferr
144 self.ferr = src.ferr
127 self.fin = src.fin
145 self.fin = src.fin
128
146
129 self._tcfg = src._tcfg.copy()
147 self._tcfg = src._tcfg.copy()
130 self._ucfg = src._ucfg.copy()
148 self._ucfg = src._ucfg.copy()
131 self._ocfg = src._ocfg.copy()
149 self._ocfg = src._ocfg.copy()
132 self._trustusers = src._trustusers.copy()
150 self._trustusers = src._trustusers.copy()
133 self._trustgroups = src._trustgroups.copy()
151 self._trustgroups = src._trustgroups.copy()
134 self.environ = src.environ
152 self.environ = src.environ
135 self.callhooks = src.callhooks
153 self.callhooks = src.callhooks
136 self.insecureconnections = src.insecureconnections
154 self.insecureconnections = src.insecureconnections
137 self.fixconfig()
155 self.fixconfig()
138
156
139 self.httppasswordmgrdb = src.httppasswordmgrdb
157 self.httppasswordmgrdb = src.httppasswordmgrdb
140 else:
158 else:
141 self.fout = util.stdout
159 self.fout = util.stdout
142 self.ferr = util.stderr
160 self.ferr = util.stderr
143 self.fin = util.stdin
161 self.fin = util.stdin
144
162
145 # shared read-only environment
163 # shared read-only environment
146 self.environ = encoding.environ
164 self.environ = encoding.environ
147
165
148 self.httppasswordmgrdb = urlreq.httppasswordmgrwithdefaultrealm()
166 self.httppasswordmgrdb = httppasswordmgrdbproxy()
149
167
150 allowed = self.configlist('experimental', 'exportableenviron')
168 allowed = self.configlist('experimental', 'exportableenviron')
151 if '*' in allowed:
169 if '*' in allowed:
152 self._exportableenviron = self.environ
170 self._exportableenviron = self.environ
153 else:
171 else:
154 self._exportableenviron = {}
172 self._exportableenviron = {}
155 for k in allowed:
173 for k in allowed:
156 if k in self.environ:
174 if k in self.environ:
157 self._exportableenviron[k] = self.environ[k]
175 self._exportableenviron[k] = self.environ[k]
158
176
159 @classmethod
177 @classmethod
160 def load(cls):
178 def load(cls):
161 """Create a ui and load global and user configs"""
179 """Create a ui and load global and user configs"""
162 u = cls()
180 u = cls()
163 # we always trust global config files
181 # we always trust global config files
164 for f in scmutil.rcpath():
182 for f in scmutil.rcpath():
165 u.readconfig(f, trust=True)
183 u.readconfig(f, trust=True)
166 return u
184 return u
167
185
168 def copy(self):
186 def copy(self):
169 return self.__class__(self)
187 return self.__class__(self)
170
188
171 def resetstate(self):
189 def resetstate(self):
172 """Clear internal state that shouldn't persist across commands"""
190 """Clear internal state that shouldn't persist across commands"""
173 if self._progbar:
191 if self._progbar:
174 self._progbar.resetstate() # reset last-print time of progress bar
192 self._progbar.resetstate() # reset last-print time of progress bar
175 self.httppasswordmgrdb = urlreq.httppasswordmgrwithdefaultrealm()
193 self.httppasswordmgrdb = httppasswordmgrdbproxy()
176
194
177 def formatter(self, topic, opts):
195 def formatter(self, topic, opts):
178 return formatter.formatter(self, topic, opts)
196 return formatter.formatter(self, topic, opts)
179
197
180 def _trusted(self, fp, f):
198 def _trusted(self, fp, f):
181 st = util.fstat(fp)
199 st = util.fstat(fp)
182 if util.isowner(st):
200 if util.isowner(st):
183 return True
201 return True
184
202
185 tusers, tgroups = self._trustusers, self._trustgroups
203 tusers, tgroups = self._trustusers, self._trustgroups
186 if '*' in tusers or '*' in tgroups:
204 if '*' in tusers or '*' in tgroups:
187 return True
205 return True
188
206
189 user = util.username(st.st_uid)
207 user = util.username(st.st_uid)
190 group = util.groupname(st.st_gid)
208 group = util.groupname(st.st_gid)
191 if user in tusers or group in tgroups or user == util.username():
209 if user in tusers or group in tgroups or user == util.username():
192 return True
210 return True
193
211
194 if self._reportuntrusted:
212 if self._reportuntrusted:
195 self.warn(_('not trusting file %s from untrusted '
213 self.warn(_('not trusting file %s from untrusted '
196 'user %s, group %s\n') % (f, user, group))
214 'user %s, group %s\n') % (f, user, group))
197 return False
215 return False
198
216
199 def readconfig(self, filename, root=None, trust=False,
217 def readconfig(self, filename, root=None, trust=False,
200 sections=None, remap=None):
218 sections=None, remap=None):
201 try:
219 try:
202 fp = open(filename, u'rb')
220 fp = open(filename, u'rb')
203 except IOError:
221 except IOError:
204 if not sections: # ignore unless we were looking for something
222 if not sections: # ignore unless we were looking for something
205 return
223 return
206 raise
224 raise
207
225
208 cfg = config.config()
226 cfg = config.config()
209 trusted = sections or trust or self._trusted(fp, filename)
227 trusted = sections or trust or self._trusted(fp, filename)
210
228
211 try:
229 try:
212 cfg.read(filename, fp, sections=sections, remap=remap)
230 cfg.read(filename, fp, sections=sections, remap=remap)
213 fp.close()
231 fp.close()
214 except error.ConfigError as inst:
232 except error.ConfigError as inst:
215 if trusted:
233 if trusted:
216 raise
234 raise
217 self.warn(_("ignored: %s\n") % str(inst))
235 self.warn(_("ignored: %s\n") % str(inst))
218
236
219 if self.plain():
237 if self.plain():
220 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
238 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
221 'logtemplate', 'statuscopies', 'style',
239 'logtemplate', 'statuscopies', 'style',
222 'traceback', 'verbose'):
240 'traceback', 'verbose'):
223 if k in cfg['ui']:
241 if k in cfg['ui']:
224 del cfg['ui'][k]
242 del cfg['ui'][k]
225 for k, v in cfg.items('defaults'):
243 for k, v in cfg.items('defaults'):
226 del cfg['defaults'][k]
244 del cfg['defaults'][k]
227 # Don't remove aliases from the configuration if in the exceptionlist
245 # Don't remove aliases from the configuration if in the exceptionlist
228 if self.plain('alias'):
246 if self.plain('alias'):
229 for k, v in cfg.items('alias'):
247 for k, v in cfg.items('alias'):
230 del cfg['alias'][k]
248 del cfg['alias'][k]
231 if self.plain('revsetalias'):
249 if self.plain('revsetalias'):
232 for k, v in cfg.items('revsetalias'):
250 for k, v in cfg.items('revsetalias'):
233 del cfg['revsetalias'][k]
251 del cfg['revsetalias'][k]
234 if self.plain('templatealias'):
252 if self.plain('templatealias'):
235 for k, v in cfg.items('templatealias'):
253 for k, v in cfg.items('templatealias'):
236 del cfg['templatealias'][k]
254 del cfg['templatealias'][k]
237
255
238 if trusted:
256 if trusted:
239 self._tcfg.update(cfg)
257 self._tcfg.update(cfg)
240 self._tcfg.update(self._ocfg)
258 self._tcfg.update(self._ocfg)
241 self._ucfg.update(cfg)
259 self._ucfg.update(cfg)
242 self._ucfg.update(self._ocfg)
260 self._ucfg.update(self._ocfg)
243
261
244 if root is None:
262 if root is None:
245 root = os.path.expanduser('~')
263 root = os.path.expanduser('~')
246 self.fixconfig(root=root)
264 self.fixconfig(root=root)
247
265
248 def fixconfig(self, root=None, section=None):
266 def fixconfig(self, root=None, section=None):
249 if section in (None, 'paths'):
267 if section in (None, 'paths'):
250 # expand vars and ~
268 # expand vars and ~
251 # translate paths relative to root (or home) into absolute paths
269 # translate paths relative to root (or home) into absolute paths
252 root = root or pycompat.getcwd()
270 root = root or pycompat.getcwd()
253 for c in self._tcfg, self._ucfg, self._ocfg:
271 for c in self._tcfg, self._ucfg, self._ocfg:
254 for n, p in c.items('paths'):
272 for n, p in c.items('paths'):
255 # Ignore sub-options.
273 # Ignore sub-options.
256 if ':' in n:
274 if ':' in n:
257 continue
275 continue
258 if not p:
276 if not p:
259 continue
277 continue
260 if '%%' in p:
278 if '%%' in p:
261 s = self.configsource('paths', n) or 'none'
279 s = self.configsource('paths', n) or 'none'
262 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
280 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
263 % (n, p, s))
281 % (n, p, s))
264 p = p.replace('%%', '%')
282 p = p.replace('%%', '%')
265 p = util.expandpath(p)
283 p = util.expandpath(p)
266 if not util.hasscheme(p) and not os.path.isabs(p):
284 if not util.hasscheme(p) and not os.path.isabs(p):
267 p = os.path.normpath(os.path.join(root, p))
285 p = os.path.normpath(os.path.join(root, p))
268 c.set("paths", n, p)
286 c.set("paths", n, p)
269
287
270 if section in (None, 'ui'):
288 if section in (None, 'ui'):
271 # update ui options
289 # update ui options
272 self.debugflag = self.configbool('ui', 'debug')
290 self.debugflag = self.configbool('ui', 'debug')
273 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
291 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
274 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
292 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
275 if self.verbose and self.quiet:
293 if self.verbose and self.quiet:
276 self.quiet = self.verbose = False
294 self.quiet = self.verbose = False
277 self._reportuntrusted = self.debugflag or self.configbool("ui",
295 self._reportuntrusted = self.debugflag or self.configbool("ui",
278 "report_untrusted", True)
296 "report_untrusted", True)
279 self.tracebackflag = self.configbool('ui', 'traceback', False)
297 self.tracebackflag = self.configbool('ui', 'traceback', False)
280
298
281 if section in (None, 'trusted'):
299 if section in (None, 'trusted'):
282 # update trust information
300 # update trust information
283 self._trustusers.update(self.configlist('trusted', 'users'))
301 self._trustusers.update(self.configlist('trusted', 'users'))
284 self._trustgroups.update(self.configlist('trusted', 'groups'))
302 self._trustgroups.update(self.configlist('trusted', 'groups'))
285
303
286 def backupconfig(self, section, item):
304 def backupconfig(self, section, item):
287 return (self._ocfg.backup(section, item),
305 return (self._ocfg.backup(section, item),
288 self._tcfg.backup(section, item),
306 self._tcfg.backup(section, item),
289 self._ucfg.backup(section, item),)
307 self._ucfg.backup(section, item),)
290 def restoreconfig(self, data):
308 def restoreconfig(self, data):
291 self._ocfg.restore(data[0])
309 self._ocfg.restore(data[0])
292 self._tcfg.restore(data[1])
310 self._tcfg.restore(data[1])
293 self._ucfg.restore(data[2])
311 self._ucfg.restore(data[2])
294
312
295 def setconfig(self, section, name, value, source=''):
313 def setconfig(self, section, name, value, source=''):
296 for cfg in (self._ocfg, self._tcfg, self._ucfg):
314 for cfg in (self._ocfg, self._tcfg, self._ucfg):
297 cfg.set(section, name, value, source)
315 cfg.set(section, name, value, source)
298 self.fixconfig(section=section)
316 self.fixconfig(section=section)
299
317
300 def _data(self, untrusted):
318 def _data(self, untrusted):
301 return untrusted and self._ucfg or self._tcfg
319 return untrusted and self._ucfg or self._tcfg
302
320
303 def configsource(self, section, name, untrusted=False):
321 def configsource(self, section, name, untrusted=False):
304 return self._data(untrusted).source(section, name)
322 return self._data(untrusted).source(section, name)
305
323
306 def config(self, section, name, default=None, untrusted=False):
324 def config(self, section, name, default=None, untrusted=False):
307 if isinstance(name, list):
325 if isinstance(name, list):
308 alternates = name
326 alternates = name
309 else:
327 else:
310 alternates = [name]
328 alternates = [name]
311
329
312 for n in alternates:
330 for n in alternates:
313 value = self._data(untrusted).get(section, n, None)
331 value = self._data(untrusted).get(section, n, None)
314 if value is not None:
332 if value is not None:
315 name = n
333 name = n
316 break
334 break
317 else:
335 else:
318 value = default
336 value = default
319
337
320 if self.debugflag and not untrusted and self._reportuntrusted:
338 if self.debugflag and not untrusted and self._reportuntrusted:
321 for n in alternates:
339 for n in alternates:
322 uvalue = self._ucfg.get(section, n)
340 uvalue = self._ucfg.get(section, n)
323 if uvalue is not None and uvalue != value:
341 if uvalue is not None and uvalue != value:
324 self.debug("ignoring untrusted configuration option "
342 self.debug("ignoring untrusted configuration option "
325 "%s.%s = %s\n" % (section, n, uvalue))
343 "%s.%s = %s\n" % (section, n, uvalue))
326 return value
344 return value
327
345
328 def configsuboptions(self, section, name, default=None, untrusted=False):
346 def configsuboptions(self, section, name, default=None, untrusted=False):
329 """Get a config option and all sub-options.
347 """Get a config option and all sub-options.
330
348
331 Some config options have sub-options that are declared with the
349 Some config options have sub-options that are declared with the
332 format "key:opt = value". This method is used to return the main
350 format "key:opt = value". This method is used to return the main
333 option and all its declared sub-options.
351 option and all its declared sub-options.
334
352
335 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
353 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
336 is a dict of defined sub-options where keys and values are strings.
354 is a dict of defined sub-options where keys and values are strings.
337 """
355 """
338 data = self._data(untrusted)
356 data = self._data(untrusted)
339 main = data.get(section, name, default)
357 main = data.get(section, name, default)
340 if self.debugflag and not untrusted and self._reportuntrusted:
358 if self.debugflag and not untrusted and self._reportuntrusted:
341 uvalue = self._ucfg.get(section, name)
359 uvalue = self._ucfg.get(section, name)
342 if uvalue is not None and uvalue != main:
360 if uvalue is not None and uvalue != main:
343 self.debug('ignoring untrusted configuration option '
361 self.debug('ignoring untrusted configuration option '
344 '%s.%s = %s\n' % (section, name, uvalue))
362 '%s.%s = %s\n' % (section, name, uvalue))
345
363
346 sub = {}
364 sub = {}
347 prefix = '%s:' % name
365 prefix = '%s:' % name
348 for k, v in data.items(section):
366 for k, v in data.items(section):
349 if k.startswith(prefix):
367 if k.startswith(prefix):
350 sub[k[len(prefix):]] = v
368 sub[k[len(prefix):]] = v
351
369
352 if self.debugflag and not untrusted and self._reportuntrusted:
370 if self.debugflag and not untrusted and self._reportuntrusted:
353 for k, v in sub.items():
371 for k, v in sub.items():
354 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
372 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
355 if uvalue is not None and uvalue != v:
373 if uvalue is not None and uvalue != v:
356 self.debug('ignoring untrusted configuration option '
374 self.debug('ignoring untrusted configuration option '
357 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
375 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
358
376
359 return main, sub
377 return main, sub
360
378
361 def configpath(self, section, name, default=None, untrusted=False):
379 def configpath(self, section, name, default=None, untrusted=False):
362 'get a path config item, expanded relative to repo root or config file'
380 'get a path config item, expanded relative to repo root or config file'
363 v = self.config(section, name, default, untrusted)
381 v = self.config(section, name, default, untrusted)
364 if v is None:
382 if v is None:
365 return None
383 return None
366 if not os.path.isabs(v) or "://" not in v:
384 if not os.path.isabs(v) or "://" not in v:
367 src = self.configsource(section, name, untrusted)
385 src = self.configsource(section, name, untrusted)
368 if ':' in src:
386 if ':' in src:
369 base = os.path.dirname(src.rsplit(':')[0])
387 base = os.path.dirname(src.rsplit(':')[0])
370 v = os.path.join(base, os.path.expanduser(v))
388 v = os.path.join(base, os.path.expanduser(v))
371 return v
389 return v
372
390
373 def configbool(self, section, name, default=False, untrusted=False):
391 def configbool(self, section, name, default=False, untrusted=False):
374 """parse a configuration element as a boolean
392 """parse a configuration element as a boolean
375
393
376 >>> u = ui(); s = 'foo'
394 >>> u = ui(); s = 'foo'
377 >>> u.setconfig(s, 'true', 'yes')
395 >>> u.setconfig(s, 'true', 'yes')
378 >>> u.configbool(s, 'true')
396 >>> u.configbool(s, 'true')
379 True
397 True
380 >>> u.setconfig(s, 'false', 'no')
398 >>> u.setconfig(s, 'false', 'no')
381 >>> u.configbool(s, 'false')
399 >>> u.configbool(s, 'false')
382 False
400 False
383 >>> u.configbool(s, 'unknown')
401 >>> u.configbool(s, 'unknown')
384 False
402 False
385 >>> u.configbool(s, 'unknown', True)
403 >>> u.configbool(s, 'unknown', True)
386 True
404 True
387 >>> u.setconfig(s, 'invalid', 'somevalue')
405 >>> u.setconfig(s, 'invalid', 'somevalue')
388 >>> u.configbool(s, 'invalid')
406 >>> u.configbool(s, 'invalid')
389 Traceback (most recent call last):
407 Traceback (most recent call last):
390 ...
408 ...
391 ConfigError: foo.invalid is not a boolean ('somevalue')
409 ConfigError: foo.invalid is not a boolean ('somevalue')
392 """
410 """
393
411
394 v = self.config(section, name, None, untrusted)
412 v = self.config(section, name, None, untrusted)
395 if v is None:
413 if v is None:
396 return default
414 return default
397 if isinstance(v, bool):
415 if isinstance(v, bool):
398 return v
416 return v
399 b = util.parsebool(v)
417 b = util.parsebool(v)
400 if b is None:
418 if b is None:
401 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
419 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
402 % (section, name, v))
420 % (section, name, v))
403 return b
421 return b
404
422
405 def configwith(self, convert, section, name, default=None,
423 def configwith(self, convert, section, name, default=None,
406 desc=None, untrusted=False):
424 desc=None, untrusted=False):
407 """parse a configuration element with a conversion function
425 """parse a configuration element with a conversion function
408
426
409 >>> u = ui(); s = 'foo'
427 >>> u = ui(); s = 'foo'
410 >>> u.setconfig(s, 'float1', '42')
428 >>> u.setconfig(s, 'float1', '42')
411 >>> u.configwith(float, s, 'float1')
429 >>> u.configwith(float, s, 'float1')
412 42.0
430 42.0
413 >>> u.setconfig(s, 'float2', '-4.25')
431 >>> u.setconfig(s, 'float2', '-4.25')
414 >>> u.configwith(float, s, 'float2')
432 >>> u.configwith(float, s, 'float2')
415 -4.25
433 -4.25
416 >>> u.configwith(float, s, 'unknown', 7)
434 >>> u.configwith(float, s, 'unknown', 7)
417 7
435 7
418 >>> u.setconfig(s, 'invalid', 'somevalue')
436 >>> u.setconfig(s, 'invalid', 'somevalue')
419 >>> u.configwith(float, s, 'invalid')
437 >>> u.configwith(float, s, 'invalid')
420 Traceback (most recent call last):
438 Traceback (most recent call last):
421 ...
439 ...
422 ConfigError: foo.invalid is not a valid float ('somevalue')
440 ConfigError: foo.invalid is not a valid float ('somevalue')
423 >>> u.configwith(float, s, 'invalid', desc='womble')
441 >>> u.configwith(float, s, 'invalid', desc='womble')
424 Traceback (most recent call last):
442 Traceback (most recent call last):
425 ...
443 ...
426 ConfigError: foo.invalid is not a valid womble ('somevalue')
444 ConfigError: foo.invalid is not a valid womble ('somevalue')
427 """
445 """
428
446
429 v = self.config(section, name, None, untrusted)
447 v = self.config(section, name, None, untrusted)
430 if v is None:
448 if v is None:
431 return default
449 return default
432 try:
450 try:
433 return convert(v)
451 return convert(v)
434 except ValueError:
452 except ValueError:
435 if desc is None:
453 if desc is None:
436 desc = convert.__name__
454 desc = convert.__name__
437 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
455 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
438 % (section, name, desc, v))
456 % (section, name, desc, v))
439
457
440 def configint(self, section, name, default=None, untrusted=False):
458 def configint(self, section, name, default=None, untrusted=False):
441 """parse a configuration element as an integer
459 """parse a configuration element as an integer
442
460
443 >>> u = ui(); s = 'foo'
461 >>> u = ui(); s = 'foo'
444 >>> u.setconfig(s, 'int1', '42')
462 >>> u.setconfig(s, 'int1', '42')
445 >>> u.configint(s, 'int1')
463 >>> u.configint(s, 'int1')
446 42
464 42
447 >>> u.setconfig(s, 'int2', '-42')
465 >>> u.setconfig(s, 'int2', '-42')
448 >>> u.configint(s, 'int2')
466 >>> u.configint(s, 'int2')
449 -42
467 -42
450 >>> u.configint(s, 'unknown', 7)
468 >>> u.configint(s, 'unknown', 7)
451 7
469 7
452 >>> u.setconfig(s, 'invalid', 'somevalue')
470 >>> u.setconfig(s, 'invalid', 'somevalue')
453 >>> u.configint(s, 'invalid')
471 >>> u.configint(s, 'invalid')
454 Traceback (most recent call last):
472 Traceback (most recent call last):
455 ...
473 ...
456 ConfigError: foo.invalid is not a valid integer ('somevalue')
474 ConfigError: foo.invalid is not a valid integer ('somevalue')
457 """
475 """
458
476
459 return self.configwith(int, section, name, default, 'integer',
477 return self.configwith(int, section, name, default, 'integer',
460 untrusted)
478 untrusted)
461
479
462 def configbytes(self, section, name, default=0, untrusted=False):
480 def configbytes(self, section, name, default=0, untrusted=False):
463 """parse a configuration element as a quantity in bytes
481 """parse a configuration element as a quantity in bytes
464
482
465 Units can be specified as b (bytes), k or kb (kilobytes), m or
483 Units can be specified as b (bytes), k or kb (kilobytes), m or
466 mb (megabytes), g or gb (gigabytes).
484 mb (megabytes), g or gb (gigabytes).
467
485
468 >>> u = ui(); s = 'foo'
486 >>> u = ui(); s = 'foo'
469 >>> u.setconfig(s, 'val1', '42')
487 >>> u.setconfig(s, 'val1', '42')
470 >>> u.configbytes(s, 'val1')
488 >>> u.configbytes(s, 'val1')
471 42
489 42
472 >>> u.setconfig(s, 'val2', '42.5 kb')
490 >>> u.setconfig(s, 'val2', '42.5 kb')
473 >>> u.configbytes(s, 'val2')
491 >>> u.configbytes(s, 'val2')
474 43520
492 43520
475 >>> u.configbytes(s, 'unknown', '7 MB')
493 >>> u.configbytes(s, 'unknown', '7 MB')
476 7340032
494 7340032
477 >>> u.setconfig(s, 'invalid', 'somevalue')
495 >>> u.setconfig(s, 'invalid', 'somevalue')
478 >>> u.configbytes(s, 'invalid')
496 >>> u.configbytes(s, 'invalid')
479 Traceback (most recent call last):
497 Traceback (most recent call last):
480 ...
498 ...
481 ConfigError: foo.invalid is not a byte quantity ('somevalue')
499 ConfigError: foo.invalid is not a byte quantity ('somevalue')
482 """
500 """
483
501
484 value = self.config(section, name)
502 value = self.config(section, name)
485 if value is None:
503 if value is None:
486 if not isinstance(default, str):
504 if not isinstance(default, str):
487 return default
505 return default
488 value = default
506 value = default
489 try:
507 try:
490 return util.sizetoint(value)
508 return util.sizetoint(value)
491 except error.ParseError:
509 except error.ParseError:
492 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
510 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
493 % (section, name, value))
511 % (section, name, value))
494
512
495 def configlist(self, section, name, default=None, untrusted=False):
513 def configlist(self, section, name, default=None, untrusted=False):
496 """parse a configuration element as a list of comma/space separated
514 """parse a configuration element as a list of comma/space separated
497 strings
515 strings
498
516
499 >>> u = ui(); s = 'foo'
517 >>> u = ui(); s = 'foo'
500 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
518 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
501 >>> u.configlist(s, 'list1')
519 >>> u.configlist(s, 'list1')
502 ['this', 'is', 'a small', 'test']
520 ['this', 'is', 'a small', 'test']
503 """
521 """
504
522
505 def _parse_plain(parts, s, offset):
523 def _parse_plain(parts, s, offset):
506 whitespace = False
524 whitespace = False
507 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
525 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
508 whitespace = True
526 whitespace = True
509 offset += 1
527 offset += 1
510 if offset >= len(s):
528 if offset >= len(s):
511 return None, parts, offset
529 return None, parts, offset
512 if whitespace:
530 if whitespace:
513 parts.append('')
531 parts.append('')
514 if s[offset] == '"' and not parts[-1]:
532 if s[offset] == '"' and not parts[-1]:
515 return _parse_quote, parts, offset + 1
533 return _parse_quote, parts, offset + 1
516 elif s[offset] == '"' and parts[-1][-1] == '\\':
534 elif s[offset] == '"' and parts[-1][-1] == '\\':
517 parts[-1] = parts[-1][:-1] + s[offset]
535 parts[-1] = parts[-1][:-1] + s[offset]
518 return _parse_plain, parts, offset + 1
536 return _parse_plain, parts, offset + 1
519 parts[-1] += s[offset]
537 parts[-1] += s[offset]
520 return _parse_plain, parts, offset + 1
538 return _parse_plain, parts, offset + 1
521
539
522 def _parse_quote(parts, s, offset):
540 def _parse_quote(parts, s, offset):
523 if offset < len(s) and s[offset] == '"': # ""
541 if offset < len(s) and s[offset] == '"': # ""
524 parts.append('')
542 parts.append('')
525 offset += 1
543 offset += 1
526 while offset < len(s) and (s[offset].isspace() or
544 while offset < len(s) and (s[offset].isspace() or
527 s[offset] == ','):
545 s[offset] == ','):
528 offset += 1
546 offset += 1
529 return _parse_plain, parts, offset
547 return _parse_plain, parts, offset
530
548
531 while offset < len(s) and s[offset] != '"':
549 while offset < len(s) and s[offset] != '"':
532 if (s[offset] == '\\' and offset + 1 < len(s)
550 if (s[offset] == '\\' and offset + 1 < len(s)
533 and s[offset + 1] == '"'):
551 and s[offset + 1] == '"'):
534 offset += 1
552 offset += 1
535 parts[-1] += '"'
553 parts[-1] += '"'
536 else:
554 else:
537 parts[-1] += s[offset]
555 parts[-1] += s[offset]
538 offset += 1
556 offset += 1
539
557
540 if offset >= len(s):
558 if offset >= len(s):
541 real_parts = _configlist(parts[-1])
559 real_parts = _configlist(parts[-1])
542 if not real_parts:
560 if not real_parts:
543 parts[-1] = '"'
561 parts[-1] = '"'
544 else:
562 else:
545 real_parts[0] = '"' + real_parts[0]
563 real_parts[0] = '"' + real_parts[0]
546 parts = parts[:-1]
564 parts = parts[:-1]
547 parts.extend(real_parts)
565 parts.extend(real_parts)
548 return None, parts, offset
566 return None, parts, offset
549
567
550 offset += 1
568 offset += 1
551 while offset < len(s) and s[offset] in [' ', ',']:
569 while offset < len(s) and s[offset] in [' ', ',']:
552 offset += 1
570 offset += 1
553
571
554 if offset < len(s):
572 if offset < len(s):
555 if offset + 1 == len(s) and s[offset] == '"':
573 if offset + 1 == len(s) and s[offset] == '"':
556 parts[-1] += '"'
574 parts[-1] += '"'
557 offset += 1
575 offset += 1
558 else:
576 else:
559 parts.append('')
577 parts.append('')
560 else:
578 else:
561 return None, parts, offset
579 return None, parts, offset
562
580
563 return _parse_plain, parts, offset
581 return _parse_plain, parts, offset
564
582
565 def _configlist(s):
583 def _configlist(s):
566 s = s.rstrip(' ,')
584 s = s.rstrip(' ,')
567 if not s:
585 if not s:
568 return []
586 return []
569 parser, parts, offset = _parse_plain, [''], 0
587 parser, parts, offset = _parse_plain, [''], 0
570 while parser:
588 while parser:
571 parser, parts, offset = parser(parts, s, offset)
589 parser, parts, offset = parser(parts, s, offset)
572 return parts
590 return parts
573
591
574 result = self.config(section, name, untrusted=untrusted)
592 result = self.config(section, name, untrusted=untrusted)
575 if result is None:
593 if result is None:
576 result = default or []
594 result = default or []
577 if isinstance(result, bytes):
595 if isinstance(result, bytes):
578 result = _configlist(result.lstrip(' ,\n'))
596 result = _configlist(result.lstrip(' ,\n'))
579 if result is None:
597 if result is None:
580 result = default or []
598 result = default or []
581 return result
599 return result
582
600
583 def hasconfig(self, section, name, untrusted=False):
601 def hasconfig(self, section, name, untrusted=False):
584 return self._data(untrusted).hasitem(section, name)
602 return self._data(untrusted).hasitem(section, name)
585
603
586 def has_section(self, section, untrusted=False):
604 def has_section(self, section, untrusted=False):
587 '''tell whether section exists in config.'''
605 '''tell whether section exists in config.'''
588 return section in self._data(untrusted)
606 return section in self._data(untrusted)
589
607
590 def configitems(self, section, untrusted=False, ignoresub=False):
608 def configitems(self, section, untrusted=False, ignoresub=False):
591 items = self._data(untrusted).items(section)
609 items = self._data(untrusted).items(section)
592 if ignoresub:
610 if ignoresub:
593 newitems = {}
611 newitems = {}
594 for k, v in items:
612 for k, v in items:
595 if ':' not in k:
613 if ':' not in k:
596 newitems[k] = v
614 newitems[k] = v
597 items = newitems.items()
615 items = newitems.items()
598 if self.debugflag and not untrusted and self._reportuntrusted:
616 if self.debugflag and not untrusted and self._reportuntrusted:
599 for k, v in self._ucfg.items(section):
617 for k, v in self._ucfg.items(section):
600 if self._tcfg.get(section, k) != v:
618 if self._tcfg.get(section, k) != v:
601 self.debug("ignoring untrusted configuration option "
619 self.debug("ignoring untrusted configuration option "
602 "%s.%s = %s\n" % (section, k, v))
620 "%s.%s = %s\n" % (section, k, v))
603 return items
621 return items
604
622
605 def walkconfig(self, untrusted=False):
623 def walkconfig(self, untrusted=False):
606 cfg = self._data(untrusted)
624 cfg = self._data(untrusted)
607 for section in cfg.sections():
625 for section in cfg.sections():
608 for name, value in self.configitems(section, untrusted):
626 for name, value in self.configitems(section, untrusted):
609 yield section, name, value
627 yield section, name, value
610
628
611 def plain(self, feature=None):
629 def plain(self, feature=None):
612 '''is plain mode active?
630 '''is plain mode active?
613
631
614 Plain mode means that all configuration variables which affect
632 Plain mode means that all configuration variables which affect
615 the behavior and output of Mercurial should be
633 the behavior and output of Mercurial should be
616 ignored. Additionally, the output should be stable,
634 ignored. Additionally, the output should be stable,
617 reproducible and suitable for use in scripts or applications.
635 reproducible and suitable for use in scripts or applications.
618
636
619 The only way to trigger plain mode is by setting either the
637 The only way to trigger plain mode is by setting either the
620 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
638 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
621
639
622 The return value can either be
640 The return value can either be
623 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
641 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
624 - True otherwise
642 - True otherwise
625 '''
643 '''
626 if ('HGPLAIN' not in encoding.environ and
644 if ('HGPLAIN' not in encoding.environ and
627 'HGPLAINEXCEPT' not in encoding.environ):
645 'HGPLAINEXCEPT' not in encoding.environ):
628 return False
646 return False
629 exceptions = encoding.environ.get('HGPLAINEXCEPT',
647 exceptions = encoding.environ.get('HGPLAINEXCEPT',
630 '').strip().split(',')
648 '').strip().split(',')
631 if feature and exceptions:
649 if feature and exceptions:
632 return feature not in exceptions
650 return feature not in exceptions
633 return True
651 return True
634
652
635 def username(self):
653 def username(self):
636 """Return default username to be used in commits.
654 """Return default username to be used in commits.
637
655
638 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
656 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
639 and stop searching if one of these is set.
657 and stop searching if one of these is set.
640 If not found and ui.askusername is True, ask the user, else use
658 If not found and ui.askusername is True, ask the user, else use
641 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
659 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
642 """
660 """
643 user = encoding.environ.get("HGUSER")
661 user = encoding.environ.get("HGUSER")
644 if user is None:
662 if user is None:
645 user = self.config("ui", ["username", "user"])
663 user = self.config("ui", ["username", "user"])
646 if user is not None:
664 if user is not None:
647 user = os.path.expandvars(user)
665 user = os.path.expandvars(user)
648 if user is None:
666 if user is None:
649 user = encoding.environ.get("EMAIL")
667 user = encoding.environ.get("EMAIL")
650 if user is None and self.configbool("ui", "askusername"):
668 if user is None and self.configbool("ui", "askusername"):
651 user = self.prompt(_("enter a commit username:"), default=None)
669 user = self.prompt(_("enter a commit username:"), default=None)
652 if user is None and not self.interactive():
670 if user is None and not self.interactive():
653 try:
671 try:
654 user = '%s@%s' % (util.getuser(), socket.getfqdn())
672 user = '%s@%s' % (util.getuser(), socket.getfqdn())
655 self.warn(_("no username found, using '%s' instead\n") % user)
673 self.warn(_("no username found, using '%s' instead\n") % user)
656 except KeyError:
674 except KeyError:
657 pass
675 pass
658 if not user:
676 if not user:
659 raise error.Abort(_('no username supplied'),
677 raise error.Abort(_('no username supplied'),
660 hint=_("use 'hg config --edit' "
678 hint=_("use 'hg config --edit' "
661 'to set your username'))
679 'to set your username'))
662 if "\n" in user:
680 if "\n" in user:
663 raise error.Abort(_("username %s contains a newline\n")
681 raise error.Abort(_("username %s contains a newline\n")
664 % repr(user))
682 % repr(user))
665 return user
683 return user
666
684
667 def shortuser(self, user):
685 def shortuser(self, user):
668 """Return a short representation of a user name or email address."""
686 """Return a short representation of a user name or email address."""
669 if not self.verbose:
687 if not self.verbose:
670 user = util.shortuser(user)
688 user = util.shortuser(user)
671 return user
689 return user
672
690
673 def expandpath(self, loc, default=None):
691 def expandpath(self, loc, default=None):
674 """Return repository location relative to cwd or from [paths]"""
692 """Return repository location relative to cwd or from [paths]"""
675 try:
693 try:
676 p = self.paths.getpath(loc)
694 p = self.paths.getpath(loc)
677 if p:
695 if p:
678 return p.rawloc
696 return p.rawloc
679 except error.RepoError:
697 except error.RepoError:
680 pass
698 pass
681
699
682 if default:
700 if default:
683 try:
701 try:
684 p = self.paths.getpath(default)
702 p = self.paths.getpath(default)
685 if p:
703 if p:
686 return p.rawloc
704 return p.rawloc
687 except error.RepoError:
705 except error.RepoError:
688 pass
706 pass
689
707
690 return loc
708 return loc
691
709
692 @util.propertycache
710 @util.propertycache
693 def paths(self):
711 def paths(self):
694 return paths(self)
712 return paths(self)
695
713
696 def pushbuffer(self, error=False, subproc=False, labeled=False):
714 def pushbuffer(self, error=False, subproc=False, labeled=False):
697 """install a buffer to capture standard output of the ui object
715 """install a buffer to capture standard output of the ui object
698
716
699 If error is True, the error output will be captured too.
717 If error is True, the error output will be captured too.
700
718
701 If subproc is True, output from subprocesses (typically hooks) will be
719 If subproc is True, output from subprocesses (typically hooks) will be
702 captured too.
720 captured too.
703
721
704 If labeled is True, any labels associated with buffered
722 If labeled is True, any labels associated with buffered
705 output will be handled. By default, this has no effect
723 output will be handled. By default, this has no effect
706 on the output returned, but extensions and GUI tools may
724 on the output returned, but extensions and GUI tools may
707 handle this argument and returned styled output. If output
725 handle this argument and returned styled output. If output
708 is being buffered so it can be captured and parsed or
726 is being buffered so it can be captured and parsed or
709 processed, labeled should not be set to True.
727 processed, labeled should not be set to True.
710 """
728 """
711 self._buffers.append([])
729 self._buffers.append([])
712 self._bufferstates.append((error, subproc, labeled))
730 self._bufferstates.append((error, subproc, labeled))
713 self._bufferapplylabels = labeled
731 self._bufferapplylabels = labeled
714
732
715 def popbuffer(self):
733 def popbuffer(self):
716 '''pop the last buffer and return the buffered output'''
734 '''pop the last buffer and return the buffered output'''
717 self._bufferstates.pop()
735 self._bufferstates.pop()
718 if self._bufferstates:
736 if self._bufferstates:
719 self._bufferapplylabels = self._bufferstates[-1][2]
737 self._bufferapplylabels = self._bufferstates[-1][2]
720 else:
738 else:
721 self._bufferapplylabels = None
739 self._bufferapplylabels = None
722
740
723 return "".join(self._buffers.pop())
741 return "".join(self._buffers.pop())
724
742
725 def write(self, *args, **opts):
743 def write(self, *args, **opts):
726 '''write args to output
744 '''write args to output
727
745
728 By default, this method simply writes to the buffer or stdout,
746 By default, this method simply writes to the buffer or stdout,
729 but extensions or GUI tools may override this method,
747 but extensions or GUI tools may override this method,
730 write_err(), popbuffer(), and label() to style output from
748 write_err(), popbuffer(), and label() to style output from
731 various parts of hg.
749 various parts of hg.
732
750
733 An optional keyword argument, "label", can be passed in.
751 An optional keyword argument, "label", can be passed in.
734 This should be a string containing label names separated by
752 This should be a string containing label names separated by
735 space. Label names take the form of "topic.type". For example,
753 space. Label names take the form of "topic.type". For example,
736 ui.debug() issues a label of "ui.debug".
754 ui.debug() issues a label of "ui.debug".
737
755
738 When labeling output for a specific command, a label of
756 When labeling output for a specific command, a label of
739 "cmdname.type" is recommended. For example, status issues
757 "cmdname.type" is recommended. For example, status issues
740 a label of "status.modified" for modified files.
758 a label of "status.modified" for modified files.
741 '''
759 '''
742 if self._buffers and not opts.get('prompt', False):
760 if self._buffers and not opts.get('prompt', False):
743 self._buffers[-1].extend(a for a in args)
761 self._buffers[-1].extend(a for a in args)
744 else:
762 else:
745 self._progclear()
763 self._progclear()
746 for a in args:
764 for a in args:
747 self.fout.write(a)
765 self.fout.write(a)
748
766
749 def write_err(self, *args, **opts):
767 def write_err(self, *args, **opts):
750 self._progclear()
768 self._progclear()
751 try:
769 try:
752 if self._bufferstates and self._bufferstates[-1][0]:
770 if self._bufferstates and self._bufferstates[-1][0]:
753 return self.write(*args, **opts)
771 return self.write(*args, **opts)
754 if not getattr(self.fout, 'closed', False):
772 if not getattr(self.fout, 'closed', False):
755 self.fout.flush()
773 self.fout.flush()
756 for a in args:
774 for a in args:
757 self.ferr.write(a)
775 self.ferr.write(a)
758 # stderr may be buffered under win32 when redirected to files,
776 # stderr may be buffered under win32 when redirected to files,
759 # including stdout.
777 # including stdout.
760 if not getattr(self.ferr, 'closed', False):
778 if not getattr(self.ferr, 'closed', False):
761 self.ferr.flush()
779 self.ferr.flush()
762 except IOError as inst:
780 except IOError as inst:
763 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
781 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
764 raise
782 raise
765
783
766 def flush(self):
784 def flush(self):
767 try: self.fout.flush()
785 try: self.fout.flush()
768 except (IOError, ValueError): pass
786 except (IOError, ValueError): pass
769 try: self.ferr.flush()
787 try: self.ferr.flush()
770 except (IOError, ValueError): pass
788 except (IOError, ValueError): pass
771
789
772 def _isatty(self, fh):
790 def _isatty(self, fh):
773 if self.configbool('ui', 'nontty', False):
791 if self.configbool('ui', 'nontty', False):
774 return False
792 return False
775 return util.isatty(fh)
793 return util.isatty(fh)
776
794
777 def interface(self, feature):
795 def interface(self, feature):
778 """what interface to use for interactive console features?
796 """what interface to use for interactive console features?
779
797
780 The interface is controlled by the value of `ui.interface` but also by
798 The interface is controlled by the value of `ui.interface` but also by
781 the value of feature-specific configuration. For example:
799 the value of feature-specific configuration. For example:
782
800
783 ui.interface.histedit = text
801 ui.interface.histedit = text
784 ui.interface.chunkselector = curses
802 ui.interface.chunkselector = curses
785
803
786 Here the features are "histedit" and "chunkselector".
804 Here the features are "histedit" and "chunkselector".
787
805
788 The configuration above means that the default interfaces for commands
806 The configuration above means that the default interfaces for commands
789 is curses, the interface for histedit is text and the interface for
807 is curses, the interface for histedit is text and the interface for
790 selecting chunk is crecord (the best curses interface available).
808 selecting chunk is crecord (the best curses interface available).
791
809
792 Consider the following example:
810 Consider the following example:
793 ui.interface = curses
811 ui.interface = curses
794 ui.interface.histedit = text
812 ui.interface.histedit = text
795
813
796 Then histedit will use the text interface and chunkselector will use
814 Then histedit will use the text interface and chunkselector will use
797 the default curses interface (crecord at the moment).
815 the default curses interface (crecord at the moment).
798 """
816 """
799 alldefaults = frozenset(["text", "curses"])
817 alldefaults = frozenset(["text", "curses"])
800
818
801 featureinterfaces = {
819 featureinterfaces = {
802 "chunkselector": [
820 "chunkselector": [
803 "text",
821 "text",
804 "curses",
822 "curses",
805 ]
823 ]
806 }
824 }
807
825
808 # Feature-specific interface
826 # Feature-specific interface
809 if feature not in featureinterfaces.keys():
827 if feature not in featureinterfaces.keys():
810 # Programming error, not user error
828 # Programming error, not user error
811 raise ValueError("Unknown feature requested %s" % feature)
829 raise ValueError("Unknown feature requested %s" % feature)
812
830
813 availableinterfaces = frozenset(featureinterfaces[feature])
831 availableinterfaces = frozenset(featureinterfaces[feature])
814 if alldefaults > availableinterfaces:
832 if alldefaults > availableinterfaces:
815 # Programming error, not user error. We need a use case to
833 # Programming error, not user error. We need a use case to
816 # define the right thing to do here.
834 # define the right thing to do here.
817 raise ValueError(
835 raise ValueError(
818 "Feature %s does not handle all default interfaces" %
836 "Feature %s does not handle all default interfaces" %
819 feature)
837 feature)
820
838
821 if self.plain():
839 if self.plain():
822 return "text"
840 return "text"
823
841
824 # Default interface for all the features
842 # Default interface for all the features
825 defaultinterface = "text"
843 defaultinterface = "text"
826 i = self.config("ui", "interface", None)
844 i = self.config("ui", "interface", None)
827 if i in alldefaults:
845 if i in alldefaults:
828 defaultinterface = i
846 defaultinterface = i
829
847
830 choseninterface = defaultinterface
848 choseninterface = defaultinterface
831 f = self.config("ui", "interface.%s" % feature, None)
849 f = self.config("ui", "interface.%s" % feature, None)
832 if f in availableinterfaces:
850 if f in availableinterfaces:
833 choseninterface = f
851 choseninterface = f
834
852
835 if i is not None and defaultinterface != i:
853 if i is not None and defaultinterface != i:
836 if f is not None:
854 if f is not None:
837 self.warn(_("invalid value for ui.interface: %s\n") %
855 self.warn(_("invalid value for ui.interface: %s\n") %
838 (i,))
856 (i,))
839 else:
857 else:
840 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
858 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
841 (i, choseninterface))
859 (i, choseninterface))
842 if f is not None and choseninterface != f:
860 if f is not None and choseninterface != f:
843 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
861 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
844 (feature, f, choseninterface))
862 (feature, f, choseninterface))
845
863
846 return choseninterface
864 return choseninterface
847
865
848 def interactive(self):
866 def interactive(self):
849 '''is interactive input allowed?
867 '''is interactive input allowed?
850
868
851 An interactive session is a session where input can be reasonably read
869 An interactive session is a session where input can be reasonably read
852 from `sys.stdin'. If this function returns false, any attempt to read
870 from `sys.stdin'. If this function returns false, any attempt to read
853 from stdin should fail with an error, unless a sensible default has been
871 from stdin should fail with an error, unless a sensible default has been
854 specified.
872 specified.
855
873
856 Interactiveness is triggered by the value of the `ui.interactive'
874 Interactiveness is triggered by the value of the `ui.interactive'
857 configuration variable or - if it is unset - when `sys.stdin' points
875 configuration variable or - if it is unset - when `sys.stdin' points
858 to a terminal device.
876 to a terminal device.
859
877
860 This function refers to input only; for output, see `ui.formatted()'.
878 This function refers to input only; for output, see `ui.formatted()'.
861 '''
879 '''
862 i = self.configbool("ui", "interactive", None)
880 i = self.configbool("ui", "interactive", None)
863 if i is None:
881 if i is None:
864 # some environments replace stdin without implementing isatty
882 # some environments replace stdin without implementing isatty
865 # usually those are non-interactive
883 # usually those are non-interactive
866 return self._isatty(self.fin)
884 return self._isatty(self.fin)
867
885
868 return i
886 return i
869
887
870 def termwidth(self):
888 def termwidth(self):
871 '''how wide is the terminal in columns?
889 '''how wide is the terminal in columns?
872 '''
890 '''
873 if 'COLUMNS' in encoding.environ:
891 if 'COLUMNS' in encoding.environ:
874 try:
892 try:
875 return int(encoding.environ['COLUMNS'])
893 return int(encoding.environ['COLUMNS'])
876 except ValueError:
894 except ValueError:
877 pass
895 pass
878 return scmutil.termsize(self)[0]
896 return scmutil.termsize(self)[0]
879
897
880 def formatted(self):
898 def formatted(self):
881 '''should formatted output be used?
899 '''should formatted output be used?
882
900
883 It is often desirable to format the output to suite the output medium.
901 It is often desirable to format the output to suite the output medium.
884 Examples of this are truncating long lines or colorizing messages.
902 Examples of this are truncating long lines or colorizing messages.
885 However, this is not often not desirable when piping output into other
903 However, this is not often not desirable when piping output into other
886 utilities, e.g. `grep'.
904 utilities, e.g. `grep'.
887
905
888 Formatted output is triggered by the value of the `ui.formatted'
906 Formatted output is triggered by the value of the `ui.formatted'
889 configuration variable or - if it is unset - when `sys.stdout' points
907 configuration variable or - if it is unset - when `sys.stdout' points
890 to a terminal device. Please note that `ui.formatted' should be
908 to a terminal device. Please note that `ui.formatted' should be
891 considered an implementation detail; it is not intended for use outside
909 considered an implementation detail; it is not intended for use outside
892 Mercurial or its extensions.
910 Mercurial or its extensions.
893
911
894 This function refers to output only; for input, see `ui.interactive()'.
912 This function refers to output only; for input, see `ui.interactive()'.
895 This function always returns false when in plain mode, see `ui.plain()'.
913 This function always returns false when in plain mode, see `ui.plain()'.
896 '''
914 '''
897 if self.plain():
915 if self.plain():
898 return False
916 return False
899
917
900 i = self.configbool("ui", "formatted", None)
918 i = self.configbool("ui", "formatted", None)
901 if i is None:
919 if i is None:
902 # some environments replace stdout without implementing isatty
920 # some environments replace stdout without implementing isatty
903 # usually those are non-interactive
921 # usually those are non-interactive
904 return self._isatty(self.fout)
922 return self._isatty(self.fout)
905
923
906 return i
924 return i
907
925
908 def _readline(self, prompt=''):
926 def _readline(self, prompt=''):
909 if self._isatty(self.fin):
927 if self._isatty(self.fin):
910 try:
928 try:
911 # magically add command line editing support, where
929 # magically add command line editing support, where
912 # available
930 # available
913 import readline
931 import readline
914 # force demandimport to really load the module
932 # force demandimport to really load the module
915 readline.read_history_file
933 readline.read_history_file
916 # windows sometimes raises something other than ImportError
934 # windows sometimes raises something other than ImportError
917 except Exception:
935 except Exception:
918 pass
936 pass
919
937
920 # call write() so output goes through subclassed implementation
938 # call write() so output goes through subclassed implementation
921 # e.g. color extension on Windows
939 # e.g. color extension on Windows
922 self.write(prompt, prompt=True)
940 self.write(prompt, prompt=True)
923
941
924 # instead of trying to emulate raw_input, swap (self.fin,
942 # instead of trying to emulate raw_input, swap (self.fin,
925 # self.fout) with (sys.stdin, sys.stdout)
943 # self.fout) with (sys.stdin, sys.stdout)
926 oldin = sys.stdin
944 oldin = sys.stdin
927 oldout = sys.stdout
945 oldout = sys.stdout
928 sys.stdin = self.fin
946 sys.stdin = self.fin
929 sys.stdout = self.fout
947 sys.stdout = self.fout
930 # prompt ' ' must exist; otherwise readline may delete entire line
948 # prompt ' ' must exist; otherwise readline may delete entire line
931 # - http://bugs.python.org/issue12833
949 # - http://bugs.python.org/issue12833
932 line = raw_input(' ')
950 line = raw_input(' ')
933 sys.stdin = oldin
951 sys.stdin = oldin
934 sys.stdout = oldout
952 sys.stdout = oldout
935
953
936 # When stdin is in binary mode on Windows, it can cause
954 # When stdin is in binary mode on Windows, it can cause
937 # raw_input() to emit an extra trailing carriage return
955 # raw_input() to emit an extra trailing carriage return
938 if os.linesep == '\r\n' and line and line[-1] == '\r':
956 if os.linesep == '\r\n' and line and line[-1] == '\r':
939 line = line[:-1]
957 line = line[:-1]
940 return line
958 return line
941
959
942 def prompt(self, msg, default="y"):
960 def prompt(self, msg, default="y"):
943 """Prompt user with msg, read response.
961 """Prompt user with msg, read response.
944 If ui is not interactive, the default is returned.
962 If ui is not interactive, the default is returned.
945 """
963 """
946 if not self.interactive():
964 if not self.interactive():
947 self.write(msg, ' ', default or '', "\n")
965 self.write(msg, ' ', default or '', "\n")
948 return default
966 return default
949 try:
967 try:
950 r = self._readline(self.label(msg, 'ui.prompt'))
968 r = self._readline(self.label(msg, 'ui.prompt'))
951 if not r:
969 if not r:
952 r = default
970 r = default
953 if self.configbool('ui', 'promptecho'):
971 if self.configbool('ui', 'promptecho'):
954 self.write(r, "\n")
972 self.write(r, "\n")
955 return r
973 return r
956 except EOFError:
974 except EOFError:
957 raise error.ResponseExpected()
975 raise error.ResponseExpected()
958
976
959 @staticmethod
977 @staticmethod
960 def extractchoices(prompt):
978 def extractchoices(prompt):
961 """Extract prompt message and list of choices from specified prompt.
979 """Extract prompt message and list of choices from specified prompt.
962
980
963 This returns tuple "(message, choices)", and "choices" is the
981 This returns tuple "(message, choices)", and "choices" is the
964 list of tuple "(response character, text without &)".
982 list of tuple "(response character, text without &)".
965
983
966 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
984 >>> ui.extractchoices("awake? $$ &Yes $$ &No")
967 ('awake? ', [('y', 'Yes'), ('n', 'No')])
985 ('awake? ', [('y', 'Yes'), ('n', 'No')])
968 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
986 >>> ui.extractchoices("line\\nbreak? $$ &Yes $$ &No")
969 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
987 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
970 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
988 >>> ui.extractchoices("want lots of $$money$$?$$Ye&s$$N&o")
971 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
989 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
972 """
990 """
973
991
974 # Sadly, the prompt string may have been built with a filename
992 # Sadly, the prompt string may have been built with a filename
975 # containing "$$" so let's try to find the first valid-looking
993 # containing "$$" so let's try to find the first valid-looking
976 # prompt to start parsing. Sadly, we also can't rely on
994 # prompt to start parsing. Sadly, we also can't rely on
977 # choices containing spaces, ASCII, or basically anything
995 # choices containing spaces, ASCII, or basically anything
978 # except an ampersand followed by a character.
996 # except an ampersand followed by a character.
979 m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
997 m = re.match(r'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
980 msg = m.group(1)
998 msg = m.group(1)
981 choices = [p.strip(' ') for p in m.group(2).split('$$')]
999 choices = [p.strip(' ') for p in m.group(2).split('$$')]
982 return (msg,
1000 return (msg,
983 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
1001 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
984 for s in choices])
1002 for s in choices])
985
1003
986 def promptchoice(self, prompt, default=0):
1004 def promptchoice(self, prompt, default=0):
987 """Prompt user with a message, read response, and ensure it matches
1005 """Prompt user with a message, read response, and ensure it matches
988 one of the provided choices. The prompt is formatted as follows:
1006 one of the provided choices. The prompt is formatted as follows:
989
1007
990 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1008 "would you like fries with that (Yn)? $$ &Yes $$ &No"
991
1009
992 The index of the choice is returned. Responses are case
1010 The index of the choice is returned. Responses are case
993 insensitive. If ui is not interactive, the default is
1011 insensitive. If ui is not interactive, the default is
994 returned.
1012 returned.
995 """
1013 """
996
1014
997 msg, choices = self.extractchoices(prompt)
1015 msg, choices = self.extractchoices(prompt)
998 resps = [r for r, t in choices]
1016 resps = [r for r, t in choices]
999 while True:
1017 while True:
1000 r = self.prompt(msg, resps[default])
1018 r = self.prompt(msg, resps[default])
1001 if r.lower() in resps:
1019 if r.lower() in resps:
1002 return resps.index(r.lower())
1020 return resps.index(r.lower())
1003 self.write(_("unrecognized response\n"))
1021 self.write(_("unrecognized response\n"))
1004
1022
1005 def getpass(self, prompt=None, default=None):
1023 def getpass(self, prompt=None, default=None):
1006 if not self.interactive():
1024 if not self.interactive():
1007 return default
1025 return default
1008 try:
1026 try:
1009 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1027 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1010 # disable getpass() only if explicitly specified. it's still valid
1028 # disable getpass() only if explicitly specified. it's still valid
1011 # to interact with tty even if fin is not a tty.
1029 # to interact with tty even if fin is not a tty.
1012 if self.configbool('ui', 'nontty'):
1030 if self.configbool('ui', 'nontty'):
1013 l = self.fin.readline()
1031 l = self.fin.readline()
1014 if not l:
1032 if not l:
1015 raise EOFError
1033 raise EOFError
1016 return l.rstrip('\n')
1034 return l.rstrip('\n')
1017 else:
1035 else:
1018 return getpass.getpass('')
1036 return getpass.getpass('')
1019 except EOFError:
1037 except EOFError:
1020 raise error.ResponseExpected()
1038 raise error.ResponseExpected()
1021 def status(self, *msg, **opts):
1039 def status(self, *msg, **opts):
1022 '''write status message to output (if ui.quiet is False)
1040 '''write status message to output (if ui.quiet is False)
1023
1041
1024 This adds an output label of "ui.status".
1042 This adds an output label of "ui.status".
1025 '''
1043 '''
1026 if not self.quiet:
1044 if not self.quiet:
1027 opts['label'] = opts.get('label', '') + ' ui.status'
1045 opts['label'] = opts.get('label', '') + ' ui.status'
1028 self.write(*msg, **opts)
1046 self.write(*msg, **opts)
1029 def warn(self, *msg, **opts):
1047 def warn(self, *msg, **opts):
1030 '''write warning message to output (stderr)
1048 '''write warning message to output (stderr)
1031
1049
1032 This adds an output label of "ui.warning".
1050 This adds an output label of "ui.warning".
1033 '''
1051 '''
1034 opts['label'] = opts.get('label', '') + ' ui.warning'
1052 opts['label'] = opts.get('label', '') + ' ui.warning'
1035 self.write_err(*msg, **opts)
1053 self.write_err(*msg, **opts)
1036 def note(self, *msg, **opts):
1054 def note(self, *msg, **opts):
1037 '''write note to output (if ui.verbose is True)
1055 '''write note to output (if ui.verbose is True)
1038
1056
1039 This adds an output label of "ui.note".
1057 This adds an output label of "ui.note".
1040 '''
1058 '''
1041 if self.verbose:
1059 if self.verbose:
1042 opts['label'] = opts.get('label', '') + ' ui.note'
1060 opts['label'] = opts.get('label', '') + ' ui.note'
1043 self.write(*msg, **opts)
1061 self.write(*msg, **opts)
1044 def debug(self, *msg, **opts):
1062 def debug(self, *msg, **opts):
1045 '''write debug message to output (if ui.debugflag is True)
1063 '''write debug message to output (if ui.debugflag is True)
1046
1064
1047 This adds an output label of "ui.debug".
1065 This adds an output label of "ui.debug".
1048 '''
1066 '''
1049 if self.debugflag:
1067 if self.debugflag:
1050 opts['label'] = opts.get('label', '') + ' ui.debug'
1068 opts['label'] = opts.get('label', '') + ' ui.debug'
1051 self.write(*msg, **opts)
1069 self.write(*msg, **opts)
1052
1070
1053 def edit(self, text, user, extra=None, editform=None, pending=None,
1071 def edit(self, text, user, extra=None, editform=None, pending=None,
1054 repopath=None):
1072 repopath=None):
1055 extra_defaults = {
1073 extra_defaults = {
1056 'prefix': 'editor',
1074 'prefix': 'editor',
1057 'suffix': '.txt',
1075 'suffix': '.txt',
1058 }
1076 }
1059 if extra is not None:
1077 if extra is not None:
1060 extra_defaults.update(extra)
1078 extra_defaults.update(extra)
1061 extra = extra_defaults
1079 extra = extra_defaults
1062
1080
1063 rdir = None
1081 rdir = None
1064 if self.configbool('experimental', 'editortmpinhg'):
1082 if self.configbool('experimental', 'editortmpinhg'):
1065 rdir = repopath
1083 rdir = repopath
1066 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1084 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1067 suffix=extra['suffix'], text=True,
1085 suffix=extra['suffix'], text=True,
1068 dir=rdir)
1086 dir=rdir)
1069 try:
1087 try:
1070 f = os.fdopen(fd, pycompat.sysstr("w"))
1088 f = os.fdopen(fd, pycompat.sysstr("w"))
1071 f.write(text)
1089 f.write(text)
1072 f.close()
1090 f.close()
1073
1091
1074 environ = {'HGUSER': user}
1092 environ = {'HGUSER': user}
1075 if 'transplant_source' in extra:
1093 if 'transplant_source' in extra:
1076 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1094 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1077 for label in ('intermediate-source', 'source', 'rebase_source'):
1095 for label in ('intermediate-source', 'source', 'rebase_source'):
1078 if label in extra:
1096 if label in extra:
1079 environ.update({'HGREVISION': extra[label]})
1097 environ.update({'HGREVISION': extra[label]})
1080 break
1098 break
1081 if editform:
1099 if editform:
1082 environ.update({'HGEDITFORM': editform})
1100 environ.update({'HGEDITFORM': editform})
1083 if pending:
1101 if pending:
1084 environ.update({'HG_PENDING': pending})
1102 environ.update({'HG_PENDING': pending})
1085
1103
1086 editor = self.geteditor()
1104 editor = self.geteditor()
1087
1105
1088 self.system("%s \"%s\"" % (editor, name),
1106 self.system("%s \"%s\"" % (editor, name),
1089 environ=environ,
1107 environ=environ,
1090 onerr=error.Abort, errprefix=_("edit failed"))
1108 onerr=error.Abort, errprefix=_("edit failed"))
1091
1109
1092 f = open(name)
1110 f = open(name)
1093 t = f.read()
1111 t = f.read()
1094 f.close()
1112 f.close()
1095 finally:
1113 finally:
1096 os.unlink(name)
1114 os.unlink(name)
1097
1115
1098 return t
1116 return t
1099
1117
1100 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None):
1118 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None):
1101 '''execute shell command with appropriate output stream. command
1119 '''execute shell command with appropriate output stream. command
1102 output will be redirected if fout is not stdout.
1120 output will be redirected if fout is not stdout.
1103 '''
1121 '''
1104 out = self.fout
1122 out = self.fout
1105 if any(s[1] for s in self._bufferstates):
1123 if any(s[1] for s in self._bufferstates):
1106 out = self
1124 out = self
1107 return util.system(cmd, environ=environ, cwd=cwd, onerr=onerr,
1125 return util.system(cmd, environ=environ, cwd=cwd, onerr=onerr,
1108 errprefix=errprefix, out=out)
1126 errprefix=errprefix, out=out)
1109
1127
1110 def traceback(self, exc=None, force=False):
1128 def traceback(self, exc=None, force=False):
1111 '''print exception traceback if traceback printing enabled or forced.
1129 '''print exception traceback if traceback printing enabled or forced.
1112 only to call in exception handler. returns true if traceback
1130 only to call in exception handler. returns true if traceback
1113 printed.'''
1131 printed.'''
1114 if self.tracebackflag or force:
1132 if self.tracebackflag or force:
1115 if exc is None:
1133 if exc is None:
1116 exc = sys.exc_info()
1134 exc = sys.exc_info()
1117 cause = getattr(exc[1], 'cause', None)
1135 cause = getattr(exc[1], 'cause', None)
1118
1136
1119 if cause is not None:
1137 if cause is not None:
1120 causetb = traceback.format_tb(cause[2])
1138 causetb = traceback.format_tb(cause[2])
1121 exctb = traceback.format_tb(exc[2])
1139 exctb = traceback.format_tb(exc[2])
1122 exconly = traceback.format_exception_only(cause[0], cause[1])
1140 exconly = traceback.format_exception_only(cause[0], cause[1])
1123
1141
1124 # exclude frame where 'exc' was chained and rethrown from exctb
1142 # exclude frame where 'exc' was chained and rethrown from exctb
1125 self.write_err('Traceback (most recent call last):\n',
1143 self.write_err('Traceback (most recent call last):\n',
1126 ''.join(exctb[:-1]),
1144 ''.join(exctb[:-1]),
1127 ''.join(causetb),
1145 ''.join(causetb),
1128 ''.join(exconly))
1146 ''.join(exconly))
1129 else:
1147 else:
1130 output = traceback.format_exception(exc[0], exc[1], exc[2])
1148 output = traceback.format_exception(exc[0], exc[1], exc[2])
1131 self.write_err(''.join(output))
1149 self.write_err(''.join(output))
1132 return self.tracebackflag or force
1150 return self.tracebackflag or force
1133
1151
1134 def geteditor(self):
1152 def geteditor(self):
1135 '''return editor to use'''
1153 '''return editor to use'''
1136 if pycompat.sysplatform == 'plan9':
1154 if pycompat.sysplatform == 'plan9':
1137 # vi is the MIPS instruction simulator on Plan 9. We
1155 # vi is the MIPS instruction simulator on Plan 9. We
1138 # instead default to E to plumb commit messages to
1156 # instead default to E to plumb commit messages to
1139 # avoid confusion.
1157 # avoid confusion.
1140 editor = 'E'
1158 editor = 'E'
1141 else:
1159 else:
1142 editor = 'vi'
1160 editor = 'vi'
1143 return (encoding.environ.get("HGEDITOR") or
1161 return (encoding.environ.get("HGEDITOR") or
1144 self.config("ui", "editor") or
1162 self.config("ui", "editor") or
1145 encoding.environ.get("VISUAL") or
1163 encoding.environ.get("VISUAL") or
1146 encoding.environ.get("EDITOR", editor))
1164 encoding.environ.get("EDITOR", editor))
1147
1165
1148 @util.propertycache
1166 @util.propertycache
1149 def _progbar(self):
1167 def _progbar(self):
1150 """setup the progbar singleton to the ui object"""
1168 """setup the progbar singleton to the ui object"""
1151 if (self.quiet or self.debugflag
1169 if (self.quiet or self.debugflag
1152 or self.configbool('progress', 'disable', False)
1170 or self.configbool('progress', 'disable', False)
1153 or not progress.shouldprint(self)):
1171 or not progress.shouldprint(self)):
1154 return None
1172 return None
1155 return getprogbar(self)
1173 return getprogbar(self)
1156
1174
1157 def _progclear(self):
1175 def _progclear(self):
1158 """clear progress bar output if any. use it before any output"""
1176 """clear progress bar output if any. use it before any output"""
1159 if '_progbar' not in vars(self): # nothing loaded yet
1177 if '_progbar' not in vars(self): # nothing loaded yet
1160 return
1178 return
1161 if self._progbar is not None and self._progbar.printed:
1179 if self._progbar is not None and self._progbar.printed:
1162 self._progbar.clear()
1180 self._progbar.clear()
1163
1181
1164 def progress(self, topic, pos, item="", unit="", total=None):
1182 def progress(self, topic, pos, item="", unit="", total=None):
1165 '''show a progress message
1183 '''show a progress message
1166
1184
1167 By default a textual progress bar will be displayed if an operation
1185 By default a textual progress bar will be displayed if an operation
1168 takes too long. 'topic' is the current operation, 'item' is a
1186 takes too long. 'topic' is the current operation, 'item' is a
1169 non-numeric marker of the current position (i.e. the currently
1187 non-numeric marker of the current position (i.e. the currently
1170 in-process file), 'pos' is the current numeric position (i.e.
1188 in-process file), 'pos' is the current numeric position (i.e.
1171 revision, bytes, etc.), unit is a corresponding unit label,
1189 revision, bytes, etc.), unit is a corresponding unit label,
1172 and total is the highest expected pos.
1190 and total is the highest expected pos.
1173
1191
1174 Multiple nested topics may be active at a time.
1192 Multiple nested topics may be active at a time.
1175
1193
1176 All topics should be marked closed by setting pos to None at
1194 All topics should be marked closed by setting pos to None at
1177 termination.
1195 termination.
1178 '''
1196 '''
1179 if self._progbar is not None:
1197 if self._progbar is not None:
1180 self._progbar.progress(topic, pos, item=item, unit=unit,
1198 self._progbar.progress(topic, pos, item=item, unit=unit,
1181 total=total)
1199 total=total)
1182 if pos is None or not self.configbool('progress', 'debug'):
1200 if pos is None or not self.configbool('progress', 'debug'):
1183 return
1201 return
1184
1202
1185 if unit:
1203 if unit:
1186 unit = ' ' + unit
1204 unit = ' ' + unit
1187 if item:
1205 if item:
1188 item = ' ' + item
1206 item = ' ' + item
1189
1207
1190 if total:
1208 if total:
1191 pct = 100.0 * pos / total
1209 pct = 100.0 * pos / total
1192 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1210 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
1193 % (topic, item, pos, total, unit, pct))
1211 % (topic, item, pos, total, unit, pct))
1194 else:
1212 else:
1195 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1213 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
1196
1214
1197 def log(self, service, *msg, **opts):
1215 def log(self, service, *msg, **opts):
1198 '''hook for logging facility extensions
1216 '''hook for logging facility extensions
1199
1217
1200 service should be a readily-identifiable subsystem, which will
1218 service should be a readily-identifiable subsystem, which will
1201 allow filtering.
1219 allow filtering.
1202
1220
1203 *msg should be a newline-terminated format string to log, and
1221 *msg should be a newline-terminated format string to log, and
1204 then any values to %-format into that format string.
1222 then any values to %-format into that format string.
1205
1223
1206 **opts currently has no defined meanings.
1224 **opts currently has no defined meanings.
1207 '''
1225 '''
1208
1226
1209 def label(self, msg, label):
1227 def label(self, msg, label):
1210 '''style msg based on supplied label
1228 '''style msg based on supplied label
1211
1229
1212 Like ui.write(), this just returns msg unchanged, but extensions
1230 Like ui.write(), this just returns msg unchanged, but extensions
1213 and GUI tools can override it to allow styling output without
1231 and GUI tools can override it to allow styling output without
1214 writing it.
1232 writing it.
1215
1233
1216 ui.write(s, 'label') is equivalent to
1234 ui.write(s, 'label') is equivalent to
1217 ui.write(ui.label(s, 'label')).
1235 ui.write(ui.label(s, 'label')).
1218 '''
1236 '''
1219 return msg
1237 return msg
1220
1238
1221 def develwarn(self, msg, stacklevel=1, config=None):
1239 def develwarn(self, msg, stacklevel=1, config=None):
1222 """issue a developer warning message
1240 """issue a developer warning message
1223
1241
1224 Use 'stacklevel' to report the offender some layers further up in the
1242 Use 'stacklevel' to report the offender some layers further up in the
1225 stack.
1243 stack.
1226 """
1244 """
1227 if not self.configbool('devel', 'all-warnings'):
1245 if not self.configbool('devel', 'all-warnings'):
1228 if config is not None and not self.configbool('devel', config):
1246 if config is not None and not self.configbool('devel', config):
1229 return
1247 return
1230 msg = 'devel-warn: ' + msg
1248 msg = 'devel-warn: ' + msg
1231 stacklevel += 1 # get in develwarn
1249 stacklevel += 1 # get in develwarn
1232 if self.tracebackflag:
1250 if self.tracebackflag:
1233 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1251 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1234 self.log('develwarn', '%s at:\n%s' %
1252 self.log('develwarn', '%s at:\n%s' %
1235 (msg, ''.join(util.getstackframes(stacklevel))))
1253 (msg, ''.join(util.getstackframes(stacklevel))))
1236 else:
1254 else:
1237 curframe = inspect.currentframe()
1255 curframe = inspect.currentframe()
1238 calframe = inspect.getouterframes(curframe, 2)
1256 calframe = inspect.getouterframes(curframe, 2)
1239 self.write_err('%s at: %s:%s (%s)\n'
1257 self.write_err('%s at: %s:%s (%s)\n'
1240 % ((msg,) + calframe[stacklevel][1:4]))
1258 % ((msg,) + calframe[stacklevel][1:4]))
1241 self.log('develwarn', '%s at: %s:%s (%s)\n',
1259 self.log('develwarn', '%s at: %s:%s (%s)\n',
1242 msg, *calframe[stacklevel][1:4])
1260 msg, *calframe[stacklevel][1:4])
1243 curframe = calframe = None # avoid cycles
1261 curframe = calframe = None # avoid cycles
1244
1262
1245 def deprecwarn(self, msg, version):
1263 def deprecwarn(self, msg, version):
1246 """issue a deprecation warning
1264 """issue a deprecation warning
1247
1265
1248 - msg: message explaining what is deprecated and how to upgrade,
1266 - msg: message explaining what is deprecated and how to upgrade,
1249 - version: last version where the API will be supported,
1267 - version: last version where the API will be supported,
1250 """
1268 """
1251 if not (self.configbool('devel', 'all-warnings')
1269 if not (self.configbool('devel', 'all-warnings')
1252 or self.configbool('devel', 'deprec-warn')):
1270 or self.configbool('devel', 'deprec-warn')):
1253 return
1271 return
1254 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1272 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1255 " update your code.)") % version
1273 " update your code.)") % version
1256 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1274 self.develwarn(msg, stacklevel=2, config='deprec-warn')
1257
1275
1258 def exportableenviron(self):
1276 def exportableenviron(self):
1259 """The environment variables that are safe to export, e.g. through
1277 """The environment variables that are safe to export, e.g. through
1260 hgweb.
1278 hgweb.
1261 """
1279 """
1262 return self._exportableenviron
1280 return self._exportableenviron
1263
1281
1264 @contextlib.contextmanager
1282 @contextlib.contextmanager
1265 def configoverride(self, overrides, source=""):
1283 def configoverride(self, overrides, source=""):
1266 """Context manager for temporary config overrides
1284 """Context manager for temporary config overrides
1267 `overrides` must be a dict of the following structure:
1285 `overrides` must be a dict of the following structure:
1268 {(section, name) : value}"""
1286 {(section, name) : value}"""
1269 backups = {}
1287 backups = {}
1270 try:
1288 try:
1271 for (section, name), value in overrides.items():
1289 for (section, name), value in overrides.items():
1272 backups[(section, name)] = self.backupconfig(section, name)
1290 backups[(section, name)] = self.backupconfig(section, name)
1273 self.setconfig(section, name, value, source)
1291 self.setconfig(section, name, value, source)
1274 yield
1292 yield
1275 finally:
1293 finally:
1276 for __, backup in backups.items():
1294 for __, backup in backups.items():
1277 self.restoreconfig(backup)
1295 self.restoreconfig(backup)
1278 # just restoring ui.quiet config to the previous value is not enough
1296 # just restoring ui.quiet config to the previous value is not enough
1279 # as it does not update ui.quiet class member
1297 # as it does not update ui.quiet class member
1280 if ('ui', 'quiet') in overrides:
1298 if ('ui', 'quiet') in overrides:
1281 self.fixconfig(section='ui')
1299 self.fixconfig(section='ui')
1282
1300
1283 class paths(dict):
1301 class paths(dict):
1284 """Represents a collection of paths and their configs.
1302 """Represents a collection of paths and their configs.
1285
1303
1286 Data is initially derived from ui instances and the config files they have
1304 Data is initially derived from ui instances and the config files they have
1287 loaded.
1305 loaded.
1288 """
1306 """
1289 def __init__(self, ui):
1307 def __init__(self, ui):
1290 dict.__init__(self)
1308 dict.__init__(self)
1291
1309
1292 for name, loc in ui.configitems('paths', ignoresub=True):
1310 for name, loc in ui.configitems('paths', ignoresub=True):
1293 # No location is the same as not existing.
1311 # No location is the same as not existing.
1294 if not loc:
1312 if not loc:
1295 continue
1313 continue
1296 loc, sub = ui.configsuboptions('paths', name)
1314 loc, sub = ui.configsuboptions('paths', name)
1297 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1315 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1298
1316
1299 def getpath(self, name, default=None):
1317 def getpath(self, name, default=None):
1300 """Return a ``path`` from a string, falling back to default.
1318 """Return a ``path`` from a string, falling back to default.
1301
1319
1302 ``name`` can be a named path or locations. Locations are filesystem
1320 ``name`` can be a named path or locations. Locations are filesystem
1303 paths or URIs.
1321 paths or URIs.
1304
1322
1305 Returns None if ``name`` is not a registered path, a URI, or a local
1323 Returns None if ``name`` is not a registered path, a URI, or a local
1306 path to a repo.
1324 path to a repo.
1307 """
1325 """
1308 # Only fall back to default if no path was requested.
1326 # Only fall back to default if no path was requested.
1309 if name is None:
1327 if name is None:
1310 if not default:
1328 if not default:
1311 default = ()
1329 default = ()
1312 elif not isinstance(default, (tuple, list)):
1330 elif not isinstance(default, (tuple, list)):
1313 default = (default,)
1331 default = (default,)
1314 for k in default:
1332 for k in default:
1315 try:
1333 try:
1316 return self[k]
1334 return self[k]
1317 except KeyError:
1335 except KeyError:
1318 continue
1336 continue
1319 return None
1337 return None
1320
1338
1321 # Most likely empty string.
1339 # Most likely empty string.
1322 # This may need to raise in the future.
1340 # This may need to raise in the future.
1323 if not name:
1341 if not name:
1324 return None
1342 return None
1325
1343
1326 try:
1344 try:
1327 return self[name]
1345 return self[name]
1328 except KeyError:
1346 except KeyError:
1329 # Try to resolve as a local path or URI.
1347 # Try to resolve as a local path or URI.
1330 try:
1348 try:
1331 # We don't pass sub-options in, so no need to pass ui instance.
1349 # We don't pass sub-options in, so no need to pass ui instance.
1332 return path(None, None, rawloc=name)
1350 return path(None, None, rawloc=name)
1333 except ValueError:
1351 except ValueError:
1334 raise error.RepoError(_('repository %s does not exist') %
1352 raise error.RepoError(_('repository %s does not exist') %
1335 name)
1353 name)
1336
1354
1337 _pathsuboptions = {}
1355 _pathsuboptions = {}
1338
1356
1339 def pathsuboption(option, attr):
1357 def pathsuboption(option, attr):
1340 """Decorator used to declare a path sub-option.
1358 """Decorator used to declare a path sub-option.
1341
1359
1342 Arguments are the sub-option name and the attribute it should set on
1360 Arguments are the sub-option name and the attribute it should set on
1343 ``path`` instances.
1361 ``path`` instances.
1344
1362
1345 The decorated function will receive as arguments a ``ui`` instance,
1363 The decorated function will receive as arguments a ``ui`` instance,
1346 ``path`` instance, and the string value of this option from the config.
1364 ``path`` instance, and the string value of this option from the config.
1347 The function should return the value that will be set on the ``path``
1365 The function should return the value that will be set on the ``path``
1348 instance.
1366 instance.
1349
1367
1350 This decorator can be used to perform additional verification of
1368 This decorator can be used to perform additional verification of
1351 sub-options and to change the type of sub-options.
1369 sub-options and to change the type of sub-options.
1352 """
1370 """
1353 def register(func):
1371 def register(func):
1354 _pathsuboptions[option] = (attr, func)
1372 _pathsuboptions[option] = (attr, func)
1355 return func
1373 return func
1356 return register
1374 return register
1357
1375
1358 @pathsuboption('pushurl', 'pushloc')
1376 @pathsuboption('pushurl', 'pushloc')
1359 def pushurlpathoption(ui, path, value):
1377 def pushurlpathoption(ui, path, value):
1360 u = util.url(value)
1378 u = util.url(value)
1361 # Actually require a URL.
1379 # Actually require a URL.
1362 if not u.scheme:
1380 if not u.scheme:
1363 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1381 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1364 return None
1382 return None
1365
1383
1366 # Don't support the #foo syntax in the push URL to declare branch to
1384 # Don't support the #foo syntax in the push URL to declare branch to
1367 # push.
1385 # push.
1368 if u.fragment:
1386 if u.fragment:
1369 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1387 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1370 'ignoring)\n') % path.name)
1388 'ignoring)\n') % path.name)
1371 u.fragment = None
1389 u.fragment = None
1372
1390
1373 return str(u)
1391 return str(u)
1374
1392
1375 @pathsuboption('pushrev', 'pushrev')
1393 @pathsuboption('pushrev', 'pushrev')
1376 def pushrevpathoption(ui, path, value):
1394 def pushrevpathoption(ui, path, value):
1377 return value
1395 return value
1378
1396
1379 class path(object):
1397 class path(object):
1380 """Represents an individual path and its configuration."""
1398 """Represents an individual path and its configuration."""
1381
1399
1382 def __init__(self, ui, name, rawloc=None, suboptions=None):
1400 def __init__(self, ui, name, rawloc=None, suboptions=None):
1383 """Construct a path from its config options.
1401 """Construct a path from its config options.
1384
1402
1385 ``ui`` is the ``ui`` instance the path is coming from.
1403 ``ui`` is the ``ui`` instance the path is coming from.
1386 ``name`` is the symbolic name of the path.
1404 ``name`` is the symbolic name of the path.
1387 ``rawloc`` is the raw location, as defined in the config.
1405 ``rawloc`` is the raw location, as defined in the config.
1388 ``pushloc`` is the raw locations pushes should be made to.
1406 ``pushloc`` is the raw locations pushes should be made to.
1389
1407
1390 If ``name`` is not defined, we require that the location be a) a local
1408 If ``name`` is not defined, we require that the location be a) a local
1391 filesystem path with a .hg directory or b) a URL. If not,
1409 filesystem path with a .hg directory or b) a URL. If not,
1392 ``ValueError`` is raised.
1410 ``ValueError`` is raised.
1393 """
1411 """
1394 if not rawloc:
1412 if not rawloc:
1395 raise ValueError('rawloc must be defined')
1413 raise ValueError('rawloc must be defined')
1396
1414
1397 # Locations may define branches via syntax <base>#<branch>.
1415 # Locations may define branches via syntax <base>#<branch>.
1398 u = util.url(rawloc)
1416 u = util.url(rawloc)
1399 branch = None
1417 branch = None
1400 if u.fragment:
1418 if u.fragment:
1401 branch = u.fragment
1419 branch = u.fragment
1402 u.fragment = None
1420 u.fragment = None
1403
1421
1404 self.url = u
1422 self.url = u
1405 self.branch = branch
1423 self.branch = branch
1406
1424
1407 self.name = name
1425 self.name = name
1408 self.rawloc = rawloc
1426 self.rawloc = rawloc
1409 self.loc = str(u)
1427 self.loc = str(u)
1410
1428
1411 # When given a raw location but not a symbolic name, validate the
1429 # When given a raw location but not a symbolic name, validate the
1412 # location is valid.
1430 # location is valid.
1413 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1431 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1414 raise ValueError('location is not a URL or path to a local '
1432 raise ValueError('location is not a URL or path to a local '
1415 'repo: %s' % rawloc)
1433 'repo: %s' % rawloc)
1416
1434
1417 suboptions = suboptions or {}
1435 suboptions = suboptions or {}
1418
1436
1419 # Now process the sub-options. If a sub-option is registered, its
1437 # Now process the sub-options. If a sub-option is registered, its
1420 # attribute will always be present. The value will be None if there
1438 # attribute will always be present. The value will be None if there
1421 # was no valid sub-option.
1439 # was no valid sub-option.
1422 for suboption, (attr, func) in _pathsuboptions.iteritems():
1440 for suboption, (attr, func) in _pathsuboptions.iteritems():
1423 if suboption not in suboptions:
1441 if suboption not in suboptions:
1424 setattr(self, attr, None)
1442 setattr(self, attr, None)
1425 continue
1443 continue
1426
1444
1427 value = func(ui, self, suboptions[suboption])
1445 value = func(ui, self, suboptions[suboption])
1428 setattr(self, attr, value)
1446 setattr(self, attr, value)
1429
1447
1430 def _isvalidlocalpath(self, path):
1448 def _isvalidlocalpath(self, path):
1431 """Returns True if the given path is a potentially valid repository.
1449 """Returns True if the given path is a potentially valid repository.
1432 This is its own function so that extensions can change the definition of
1450 This is its own function so that extensions can change the definition of
1433 'valid' in this case (like when pulling from a git repo into a hg
1451 'valid' in this case (like when pulling from a git repo into a hg
1434 one)."""
1452 one)."""
1435 return os.path.isdir(os.path.join(path, '.hg'))
1453 return os.path.isdir(os.path.join(path, '.hg'))
1436
1454
1437 @property
1455 @property
1438 def suboptions(self):
1456 def suboptions(self):
1439 """Return sub-options and their values for this path.
1457 """Return sub-options and their values for this path.
1440
1458
1441 This is intended to be used for presentation purposes.
1459 This is intended to be used for presentation purposes.
1442 """
1460 """
1443 d = {}
1461 d = {}
1444 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1462 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1445 value = getattr(self, attr)
1463 value = getattr(self, attr)
1446 if value is not None:
1464 if value is not None:
1447 d[subopt] = value
1465 d[subopt] = value
1448 return d
1466 return d
1449
1467
1450 # we instantiate one globally shared progress bar to avoid
1468 # we instantiate one globally shared progress bar to avoid
1451 # competing progress bars when multiple UI objects get created
1469 # competing progress bars when multiple UI objects get created
1452 _progresssingleton = None
1470 _progresssingleton = None
1453
1471
1454 def getprogbar(ui):
1472 def getprogbar(ui):
1455 global _progresssingleton
1473 global _progresssingleton
1456 if _progresssingleton is None:
1474 if _progresssingleton is None:
1457 # passing 'ui' object to the singleton is fishy,
1475 # passing 'ui' object to the singleton is fishy,
1458 # this is how the extension used to work but feel free to rework it.
1476 # this is how the extension used to work but feel free to rework it.
1459 _progresssingleton = progress.progbar(ui)
1477 _progresssingleton = progress.progbar(ui)
1460 return _progresssingleton
1478 return _progresssingleton
General Comments 0
You need to be logged in to leave comments. Login now