##// END OF EJS Templates
fix indentation error
Benoit Boissinot -
r12665:cf24b6b5 default
parent child Browse files
Show More
@@ -1,612 +1,612 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, util, error
10 import config, util, error
11
11
12 class ui(object):
12 class ui(object):
13 def __init__(self, src=None):
13 def __init__(self, src=None):
14 self._buffers = []
14 self._buffers = []
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
16 self._reportuntrusted = True
16 self._reportuntrusted = True
17 self._ocfg = config.config() # overlay
17 self._ocfg = config.config() # overlay
18 self._tcfg = config.config() # trusted
18 self._tcfg = config.config() # trusted
19 self._ucfg = config.config() # untrusted
19 self._ucfg = config.config() # untrusted
20 self._trustusers = set()
20 self._trustusers = set()
21 self._trustgroups = set()
21 self._trustgroups = set()
22
22
23 if src:
23 if src:
24 self._tcfg = src._tcfg.copy()
24 self._tcfg = src._tcfg.copy()
25 self._ucfg = src._ucfg.copy()
25 self._ucfg = src._ucfg.copy()
26 self._ocfg = src._ocfg.copy()
26 self._ocfg = src._ocfg.copy()
27 self._trustusers = src._trustusers.copy()
27 self._trustusers = src._trustusers.copy()
28 self._trustgroups = src._trustgroups.copy()
28 self._trustgroups = src._trustgroups.copy()
29 self.environ = src.environ
29 self.environ = src.environ
30 self.fixconfig()
30 self.fixconfig()
31 else:
31 else:
32 # shared read-only environment
32 # shared read-only environment
33 self.environ = os.environ
33 self.environ = os.environ
34 # we always trust global config files
34 # we always trust global config files
35 for f in util.rcpath():
35 for f in util.rcpath():
36 self.readconfig(f, trust=True)
36 self.readconfig(f, trust=True)
37
37
38 def copy(self):
38 def copy(self):
39 return self.__class__(self)
39 return self.__class__(self)
40
40
41 def _is_trusted(self, fp, f):
41 def _is_trusted(self, fp, f):
42 st = util.fstat(fp)
42 st = util.fstat(fp)
43 if util.isowner(st):
43 if util.isowner(st):
44 return True
44 return True
45
45
46 tusers, tgroups = self._trustusers, self._trustgroups
46 tusers, tgroups = self._trustusers, self._trustgroups
47 if '*' in tusers or '*' in tgroups:
47 if '*' in tusers or '*' in tgroups:
48 return True
48 return True
49
49
50 user = util.username(st.st_uid)
50 user = util.username(st.st_uid)
51 group = util.groupname(st.st_gid)
51 group = util.groupname(st.st_gid)
52 if user in tusers or group in tgroups or user == util.username():
52 if user in tusers or group in tgroups or user == util.username():
53 return True
53 return True
54
54
55 if self._reportuntrusted:
55 if self._reportuntrusted:
56 self.warn(_('Not trusting file %s from untrusted '
56 self.warn(_('Not trusting file %s from untrusted '
57 'user %s, group %s\n') % (f, user, group))
57 'user %s, group %s\n') % (f, user, group))
58 return False
58 return False
59
59
60 def readconfig(self, filename, root=None, trust=False,
60 def readconfig(self, filename, root=None, trust=False,
61 sections=None, remap=None):
61 sections=None, remap=None):
62 try:
62 try:
63 fp = open(filename)
63 fp = open(filename)
64 except IOError:
64 except IOError:
65 if not sections: # ignore unless we were looking for something
65 if not sections: # ignore unless we were looking for something
66 return
66 return
67 raise
67 raise
68
68
69 cfg = config.config()
69 cfg = config.config()
70 trusted = sections or trust or self._is_trusted(fp, filename)
70 trusted = sections or trust or self._is_trusted(fp, filename)
71
71
72 try:
72 try:
73 cfg.read(filename, fp, sections=sections, remap=remap)
73 cfg.read(filename, fp, sections=sections, remap=remap)
74 except error.ConfigError, inst:
74 except error.ConfigError, inst:
75 if trusted:
75 if trusted:
76 raise
76 raise
77 self.warn(_("Ignored: %s\n") % str(inst))
77 self.warn(_("Ignored: %s\n") % str(inst))
78
78
79 if self.plain():
79 if self.plain():
80 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
80 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
81 'logtemplate', 'style',
81 'logtemplate', 'style',
82 'traceback', 'verbose'):
82 'traceback', 'verbose'):
83 if k in cfg['ui']:
83 if k in cfg['ui']:
84 del cfg['ui'][k]
84 del cfg['ui'][k]
85 for k, v in cfg.items('alias'):
85 for k, v in cfg.items('alias'):
86 del cfg['alias'][k]
86 del cfg['alias'][k]
87 for k, v in cfg.items('defaults'):
87 for k, v in cfg.items('defaults'):
88 del cfg['defaults'][k]
88 del cfg['defaults'][k]
89
89
90 if trusted:
90 if trusted:
91 self._tcfg.update(cfg)
91 self._tcfg.update(cfg)
92 self._tcfg.update(self._ocfg)
92 self._tcfg.update(self._ocfg)
93 self._ucfg.update(cfg)
93 self._ucfg.update(cfg)
94 self._ucfg.update(self._ocfg)
94 self._ucfg.update(self._ocfg)
95
95
96 if root is None:
96 if root is None:
97 root = os.path.expanduser('~')
97 root = os.path.expanduser('~')
98 self.fixconfig(root=root)
98 self.fixconfig(root=root)
99
99
100 def fixconfig(self, root=None):
100 def fixconfig(self, root=None):
101 # expand vars and ~
101 # expand vars and ~
102 # translate paths relative to root (or home) into absolute paths
102 # translate paths relative to root (or home) into absolute paths
103 root = root or os.getcwd()
103 root = root or os.getcwd()
104 for c in self._tcfg, self._ucfg, self._ocfg:
104 for c in self._tcfg, self._ucfg, self._ocfg:
105 for n, p in c.items('paths'):
105 for n, p in c.items('paths'):
106 if not p:
106 if not p:
107 continue
107 continue
108 if '%%' in p:
108 if '%%' in p:
109 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
109 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
110 % (n, p, self.configsource('paths', n)))
110 % (n, p, self.configsource('paths', n)))
111 p = p.replace('%%', '%')
111 p = p.replace('%%', '%')
112 p = util.expandpath(p)
112 p = util.expandpath(p)
113 if '://' not in p and not os.path.isabs(p):
113 if '://' not in p and not os.path.isabs(p):
114 p = os.path.normpath(os.path.join(root, p))
114 p = os.path.normpath(os.path.join(root, p))
115 c.set("paths", n, p)
115 c.set("paths", n, p)
116
116
117 # update ui options
117 # update ui options
118 self.debugflag = self.configbool('ui', 'debug')
118 self.debugflag = self.configbool('ui', 'debug')
119 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
119 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
120 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
120 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
121 if self.verbose and self.quiet:
121 if self.verbose and self.quiet:
122 self.quiet = self.verbose = False
122 self.quiet = self.verbose = False
123 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
123 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
124 self.tracebackflag = self.configbool('ui', 'traceback', False)
124 self.tracebackflag = self.configbool('ui', 'traceback', False)
125
125
126 # update trust information
126 # update trust information
127 self._trustusers.update(self.configlist('trusted', 'users'))
127 self._trustusers.update(self.configlist('trusted', 'users'))
128 self._trustgroups.update(self.configlist('trusted', 'groups'))
128 self._trustgroups.update(self.configlist('trusted', 'groups'))
129
129
130 def setconfig(self, section, name, value, overlay=True):
130 def setconfig(self, section, name, value, overlay=True):
131 if overlay:
131 if overlay:
132 self._ocfg.set(section, name, value)
132 self._ocfg.set(section, name, value)
133 self._tcfg.set(section, name, value)
133 self._tcfg.set(section, name, value)
134 self._ucfg.set(section, name, value)
134 self._ucfg.set(section, name, value)
135 self.fixconfig()
135 self.fixconfig()
136
136
137 def _data(self, untrusted):
137 def _data(self, untrusted):
138 return untrusted and self._ucfg or self._tcfg
138 return untrusted and self._ucfg or self._tcfg
139
139
140 def configsource(self, section, name, untrusted=False):
140 def configsource(self, section, name, untrusted=False):
141 return self._data(untrusted).source(section, name) or 'none'
141 return self._data(untrusted).source(section, name) or 'none'
142
142
143 def config(self, section, name, default=None, untrusted=False):
143 def config(self, section, name, default=None, untrusted=False):
144 value = self._data(untrusted).get(section, name, default)
144 value = self._data(untrusted).get(section, name, default)
145 if self.debugflag and not untrusted and self._reportuntrusted:
145 if self.debugflag and not untrusted and self._reportuntrusted:
146 uvalue = self._ucfg.get(section, name)
146 uvalue = self._ucfg.get(section, name)
147 if uvalue is not None and uvalue != value:
147 if uvalue is not None and uvalue != value:
148 self.debug(_("ignoring untrusted configuration option "
148 self.debug(_("ignoring untrusted configuration option "
149 "%s.%s = %s\n") % (section, name, uvalue))
149 "%s.%s = %s\n") % (section, name, uvalue))
150 return value
150 return value
151
151
152 def configbool(self, section, name, default=False, untrusted=False):
152 def configbool(self, section, name, default=False, untrusted=False):
153 v = self.config(section, name, None, untrusted)
153 v = self.config(section, name, None, untrusted)
154 if v is None:
154 if v is None:
155 return default
155 return default
156 if isinstance(v, bool):
156 if isinstance(v, bool):
157 return v
157 return v
158 b = util.parsebool(v)
158 b = util.parsebool(v)
159 if b is None:
159 if b is None:
160 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
160 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
161 % (section, name, v))
161 % (section, name, v))
162 return b
162 return b
163
163
164 def configlist(self, section, name, default=None, untrusted=False):
164 def configlist(self, section, name, default=None, untrusted=False):
165 """Return a list of comma/space separated strings"""
165 """Return a list of comma/space separated strings"""
166
166
167 def _parse_plain(parts, s, offset):
167 def _parse_plain(parts, s, offset):
168 whitespace = False
168 whitespace = False
169 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
169 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
170 whitespace = True
170 whitespace = True
171 offset += 1
171 offset += 1
172 if offset >= len(s):
172 if offset >= len(s):
173 return None, parts, offset
173 return None, parts, offset
174 if whitespace:
174 if whitespace:
175 parts.append('')
175 parts.append('')
176 if s[offset] == '"' and not parts[-1]:
176 if s[offset] == '"' and not parts[-1]:
177 return _parse_quote, parts, offset + 1
177 return _parse_quote, parts, offset + 1
178 elif s[offset] == '"' and parts[-1][-1] == '\\':
178 elif s[offset] == '"' and parts[-1][-1] == '\\':
179 parts[-1] = parts[-1][:-1] + s[offset]
179 parts[-1] = parts[-1][:-1] + s[offset]
180 return _parse_plain, parts, offset + 1
180 return _parse_plain, parts, offset + 1
181 parts[-1] += s[offset]
181 parts[-1] += s[offset]
182 return _parse_plain, parts, offset + 1
182 return _parse_plain, parts, offset + 1
183
183
184 def _parse_quote(parts, s, offset):
184 def _parse_quote(parts, s, offset):
185 if offset < len(s) and s[offset] == '"': # ""
185 if offset < len(s) and s[offset] == '"': # ""
186 parts.append('')
186 parts.append('')
187 offset += 1
187 offset += 1
188 while offset < len(s) and (s[offset].isspace() or
188 while offset < len(s) and (s[offset].isspace() or
189 s[offset] == ','):
189 s[offset] == ','):
190 offset += 1
190 offset += 1
191 return _parse_plain, parts, offset
191 return _parse_plain, parts, offset
192
192
193 while offset < len(s) and s[offset] != '"':
193 while offset < len(s) and s[offset] != '"':
194 if (s[offset] == '\\' and offset + 1 < len(s)
194 if (s[offset] == '\\' and offset + 1 < len(s)
195 and s[offset + 1] == '"'):
195 and s[offset + 1] == '"'):
196 offset += 1
196 offset += 1
197 parts[-1] += '"'
197 parts[-1] += '"'
198 else:
198 else:
199 parts[-1] += s[offset]
199 parts[-1] += s[offset]
200 offset += 1
200 offset += 1
201
201
202 if offset >= len(s):
202 if offset >= len(s):
203 real_parts = _configlist(parts[-1])
203 real_parts = _configlist(parts[-1])
204 if not real_parts:
204 if not real_parts:
205 parts[-1] = '"'
205 parts[-1] = '"'
206 else:
206 else:
207 real_parts[0] = '"' + real_parts[0]
207 real_parts[0] = '"' + real_parts[0]
208 parts = parts[:-1]
208 parts = parts[:-1]
209 parts.extend(real_parts)
209 parts.extend(real_parts)
210 return None, parts, offset
210 return None, parts, offset
211
211
212 offset += 1
212 offset += 1
213 while offset < len(s) and s[offset] in [' ', ',']:
213 while offset < len(s) and s[offset] in [' ', ',']:
214 offset += 1
214 offset += 1
215
215
216 if offset < len(s):
216 if offset < len(s):
217 if offset + 1 == len(s) and s[offset] == '"':
217 if offset + 1 == len(s) and s[offset] == '"':
218 parts[-1] += '"'
218 parts[-1] += '"'
219 offset += 1
219 offset += 1
220 else:
220 else:
221 parts.append('')
221 parts.append('')
222 else:
222 else:
223 return None, parts, offset
223 return None, parts, offset
224
224
225 return _parse_plain, parts, offset
225 return _parse_plain, parts, offset
226
226
227 def _configlist(s):
227 def _configlist(s):
228 s = s.rstrip(' ,')
228 s = s.rstrip(' ,')
229 if not s:
229 if not s:
230 return []
230 return []
231 parser, parts, offset = _parse_plain, [''], 0
231 parser, parts, offset = _parse_plain, [''], 0
232 while parser:
232 while parser:
233 parser, parts, offset = parser(parts, s, offset)
233 parser, parts, offset = parser(parts, s, offset)
234 return parts
234 return parts
235
235
236 result = self.config(section, name, untrusted=untrusted)
236 result = self.config(section, name, untrusted=untrusted)
237 if result is None:
237 if result is None:
238 result = default or []
238 result = default or []
239 if isinstance(result, basestring):
239 if isinstance(result, basestring):
240 result = _configlist(result.lstrip(' ,\n'))
240 result = _configlist(result.lstrip(' ,\n'))
241 if result is None:
241 if result is None:
242 result = default or []
242 result = default or []
243 return result
243 return result
244
244
245 def has_section(self, section, untrusted=False):
245 def has_section(self, section, untrusted=False):
246 '''tell whether section exists in config.'''
246 '''tell whether section exists in config.'''
247 return section in self._data(untrusted)
247 return section in self._data(untrusted)
248
248
249 def configitems(self, section, untrusted=False):
249 def configitems(self, section, untrusted=False):
250 items = self._data(untrusted).items(section)
250 items = self._data(untrusted).items(section)
251 if self.debugflag and not untrusted and self._reportuntrusted:
251 if self.debugflag and not untrusted and self._reportuntrusted:
252 for k, v in self._ucfg.items(section):
252 for k, v in self._ucfg.items(section):
253 if self._tcfg.get(section, k) != v:
253 if self._tcfg.get(section, k) != v:
254 self.debug(_("ignoring untrusted configuration option "
254 self.debug(_("ignoring untrusted configuration option "
255 "%s.%s = %s\n") % (section, k, v))
255 "%s.%s = %s\n") % (section, k, v))
256 return items
256 return items
257
257
258 def walkconfig(self, untrusted=False):
258 def walkconfig(self, untrusted=False):
259 cfg = self._data(untrusted)
259 cfg = self._data(untrusted)
260 for section in cfg.sections():
260 for section in cfg.sections():
261 for name, value in self.configitems(section, untrusted):
261 for name, value in self.configitems(section, untrusted):
262 yield section, name, str(value).replace('\n', '\\n')
262 yield section, name, str(value).replace('\n', '\\n')
263
263
264 def plain(self):
264 def plain(self):
265 '''is plain mode active?
265 '''is plain mode active?
266
266
267 Plain mode means that all configuration variables which affect the
267 Plain mode means that all configuration variables which affect the
268 behavior and output of Mercurial should be ignored. Additionally, the
268 behavior and output of Mercurial should be ignored. Additionally, the
269 output should be stable, reproducible and suitable for use in scripts or
269 output should be stable, reproducible and suitable for use in scripts or
270 applications.
270 applications.
271
271
272 The only way to trigger plain mode is by setting the `HGPLAIN'
272 The only way to trigger plain mode is by setting the `HGPLAIN'
273 environment variable.
273 environment variable.
274 '''
274 '''
275 return 'HGPLAIN' in os.environ
275 return 'HGPLAIN' in os.environ
276
276
277 def username(self):
277 def username(self):
278 """Return default username to be used in commits.
278 """Return default username to be used in commits.
279
279
280 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
280 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
281 and stop searching if one of these is set.
281 and stop searching if one of these is set.
282 If not found and ui.askusername is True, ask the user, else use
282 If not found and ui.askusername is True, ask the user, else use
283 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
283 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
284 """
284 """
285 user = os.environ.get("HGUSER")
285 user = os.environ.get("HGUSER")
286 if user is None:
286 if user is None:
287 user = self.config("ui", "username")
287 user = self.config("ui", "username")
288 if user is not None:
288 if user is not None:
289 user = os.path.expandvars(user)
289 user = os.path.expandvars(user)
290 if user is None:
290 if user is None:
291 user = os.environ.get("EMAIL")
291 user = os.environ.get("EMAIL")
292 if user is None and self.configbool("ui", "askusername"):
292 if user is None and self.configbool("ui", "askusername"):
293 user = self.prompt(_("enter a commit username:"), default=None)
293 user = self.prompt(_("enter a commit username:"), default=None)
294 if user is None and not self.interactive():
294 if user is None and not self.interactive():
295 try:
295 try:
296 user = '%s@%s' % (util.getuser(), socket.getfqdn())
296 user = '%s@%s' % (util.getuser(), socket.getfqdn())
297 self.warn(_("No username found, using '%s' instead\n") % user)
297 self.warn(_("No username found, using '%s' instead\n") % user)
298 except KeyError:
298 except KeyError:
299 pass
299 pass
300 if not user:
300 if not user:
301 raise util.Abort(_('no username supplied (see "hg help config")'))
301 raise util.Abort(_('no username supplied (see "hg help config")'))
302 if "\n" in user:
302 if "\n" in user:
303 raise util.Abort(_("username %s contains a newline\n") % repr(user))
303 raise util.Abort(_("username %s contains a newline\n") % repr(user))
304 return user
304 return user
305
305
306 def shortuser(self, user):
306 def shortuser(self, user):
307 """Return a short representation of a user name or email address."""
307 """Return a short representation of a user name or email address."""
308 if not self.verbose:
308 if not self.verbose:
309 user = util.shortuser(user)
309 user = util.shortuser(user)
310 return user
310 return user
311
311
312 def expandpath(self, loc, default=None):
312 def expandpath(self, loc, default=None):
313 """Return repository location relative to cwd or from [paths]"""
313 """Return repository location relative to cwd or from [paths]"""
314 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
314 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
315 return loc
315 return loc
316
316
317 path = self.config('paths', loc)
317 path = self.config('paths', loc)
318 if not path and default is not None:
318 if not path and default is not None:
319 path = self.config('paths', default)
319 path = self.config('paths', default)
320 return path or loc
320 return path or loc
321
321
322 def pushbuffer(self):
322 def pushbuffer(self):
323 self._buffers.append([])
323 self._buffers.append([])
324
324
325 def popbuffer(self, labeled=False):
325 def popbuffer(self, labeled=False):
326 '''pop the last buffer and return the buffered output
326 '''pop the last buffer and return the buffered output
327
327
328 If labeled is True, any labels associated with buffered
328 If labeled is True, any labels associated with buffered
329 output will be handled. By default, this has no effect
329 output will be handled. By default, this has no effect
330 on the output returned, but extensions and GUI tools may
330 on the output returned, but extensions and GUI tools may
331 handle this argument and returned styled output. If output
331 handle this argument and returned styled output. If output
332 is being buffered so it can be captured and parsed or
332 is being buffered so it can be captured and parsed or
333 processed, labeled should not be set to True.
333 processed, labeled should not be set to True.
334 '''
334 '''
335 return "".join(self._buffers.pop())
335 return "".join(self._buffers.pop())
336
336
337 def write(self, *args, **opts):
337 def write(self, *args, **opts):
338 '''write args to output
338 '''write args to output
339
339
340 By default, this method simply writes to the buffer or stdout,
340 By default, this method simply writes to the buffer or stdout,
341 but extensions or GUI tools may override this method,
341 but extensions or GUI tools may override this method,
342 write_err(), popbuffer(), and label() to style output from
342 write_err(), popbuffer(), and label() to style output from
343 various parts of hg.
343 various parts of hg.
344
344
345 An optional keyword argument, "label", can be passed in.
345 An optional keyword argument, "label", can be passed in.
346 This should be a string containing label names separated by
346 This should be a string containing label names separated by
347 space. Label names take the form of "topic.type". For example,
347 space. Label names take the form of "topic.type". For example,
348 ui.debug() issues a label of "ui.debug".
348 ui.debug() issues a label of "ui.debug".
349
349
350 When labeling output for a specific command, a label of
350 When labeling output for a specific command, a label of
351 "cmdname.type" is recommended. For example, status issues
351 "cmdname.type" is recommended. For example, status issues
352 a label of "status.modified" for modified files.
352 a label of "status.modified" for modified files.
353 '''
353 '''
354 if self._buffers:
354 if self._buffers:
355 self._buffers[-1].extend([str(a) for a in args])
355 self._buffers[-1].extend([str(a) for a in args])
356 else:
356 else:
357 for a in args:
357 for a in args:
358 sys.stdout.write(str(a))
358 sys.stdout.write(str(a))
359
359
360 def write_err(self, *args, **opts):
360 def write_err(self, *args, **opts):
361 try:
361 try:
362 if not getattr(sys.stdout, 'closed', False):
362 if not getattr(sys.stdout, 'closed', False):
363 sys.stdout.flush()
363 sys.stdout.flush()
364 for a in args:
364 for a in args:
365 sys.stderr.write(str(a))
365 sys.stderr.write(str(a))
366 # stderr may be buffered under win32 when redirected to files,
366 # stderr may be buffered under win32 when redirected to files,
367 # including stdout.
367 # including stdout.
368 if not getattr(sys.stderr, 'closed', False):
368 if not getattr(sys.stderr, 'closed', False):
369 sys.stderr.flush()
369 sys.stderr.flush()
370 except IOError, inst:
370 except IOError, inst:
371 if inst.errno not in (errno.EPIPE, errno.EIO):
371 if inst.errno not in (errno.EPIPE, errno.EIO):
372 raise
372 raise
373
373
374 def flush(self):
374 def flush(self):
375 try: sys.stdout.flush()
375 try: sys.stdout.flush()
376 except: pass
376 except: pass
377 try: sys.stderr.flush()
377 try: sys.stderr.flush()
378 except: pass
378 except: pass
379
379
380 def interactive(self):
380 def interactive(self):
381 '''is interactive input allowed?
381 '''is interactive input allowed?
382
382
383 An interactive session is a session where input can be reasonably read
383 An interactive session is a session where input can be reasonably read
384 from `sys.stdin'. If this function returns false, any attempt to read
384 from `sys.stdin'. If this function returns false, any attempt to read
385 from stdin should fail with an error, unless a sensible default has been
385 from stdin should fail with an error, unless a sensible default has been
386 specified.
386 specified.
387
387
388 Interactiveness is triggered by the value of the `ui.interactive'
388 Interactiveness is triggered by the value of the `ui.interactive'
389 configuration variable or - if it is unset - when `sys.stdin' points
389 configuration variable or - if it is unset - when `sys.stdin' points
390 to a terminal device.
390 to a terminal device.
391
391
392 This function refers to input only; for output, see `ui.formatted()'.
392 This function refers to input only; for output, see `ui.formatted()'.
393 '''
393 '''
394 i = self.configbool("ui", "interactive", None)
394 i = self.configbool("ui", "interactive", None)
395 if i is None:
395 if i is None:
396 try:
396 try:
397 return sys.stdin.isatty()
397 return sys.stdin.isatty()
398 except AttributeError:
398 except AttributeError:
399 # some environments replace stdin without implementing isatty
399 # some environments replace stdin without implementing isatty
400 # usually those are non-interactive
400 # usually those are non-interactive
401 return False
401 return False
402
402
403 return i
403 return i
404
404
405 def formatted(self):
405 def formatted(self):
406 '''should formatted output be used?
406 '''should formatted output be used?
407
407
408 It is often desirable to format the output to suite the output medium.
408 It is often desirable to format the output to suite the output medium.
409 Examples of this are truncating long lines or colorizing messages.
409 Examples of this are truncating long lines or colorizing messages.
410 However, this is not often not desirable when piping output into other
410 However, this is not often not desirable when piping output into other
411 utilities, e.g. `grep'.
411 utilities, e.g. `grep'.
412
412
413 Formatted output is triggered by the value of the `ui.formatted'
413 Formatted output is triggered by the value of the `ui.formatted'
414 configuration variable or - if it is unset - when `sys.stdout' points
414 configuration variable or - if it is unset - when `sys.stdout' points
415 to a terminal device. Please note that `ui.formatted' should be
415 to a terminal device. Please note that `ui.formatted' should be
416 considered an implementation detail; it is not intended for use outside
416 considered an implementation detail; it is not intended for use outside
417 Mercurial or its extensions.
417 Mercurial or its extensions.
418
418
419 This function refers to output only; for input, see `ui.interactive()'.
419 This function refers to output only; for input, see `ui.interactive()'.
420 This function always returns false when in plain mode, see `ui.plain()'.
420 This function always returns false when in plain mode, see `ui.plain()'.
421 '''
421 '''
422 if self.plain():
422 if self.plain():
423 return False
423 return False
424
424
425 i = self.configbool("ui", "formatted", None)
425 i = self.configbool("ui", "formatted", None)
426 if i is None:
426 if i is None:
427 try:
427 try:
428 return sys.stdout.isatty()
428 return sys.stdout.isatty()
429 except AttributeError:
429 except AttributeError:
430 # some environments replace stdout without implementing isatty
430 # some environments replace stdout without implementing isatty
431 # usually those are non-interactive
431 # usually those are non-interactive
432 return False
432 return False
433
433
434 return i
434 return i
435
435
436 def _readline(self, prompt=''):
436 def _readline(self, prompt=''):
437 if sys.stdin.isatty():
437 if sys.stdin.isatty():
438 try:
438 try:
439 # magically add command line editing support, where
439 # magically add command line editing support, where
440 # available
440 # available
441 import readline
441 import readline
442 # force demandimport to really load the module
442 # force demandimport to really load the module
443 readline.read_history_file
443 readline.read_history_file
444 # windows sometimes raises something other than ImportError
444 # windows sometimes raises something other than ImportError
445 except Exception:
445 except Exception:
446 pass
446 pass
447 line = raw_input(prompt)
447 line = raw_input(prompt)
448 # When stdin is in binary mode on Windows, it can cause
448 # When stdin is in binary mode on Windows, it can cause
449 # raw_input() to emit an extra trailing carriage return
449 # raw_input() to emit an extra trailing carriage return
450 if os.linesep == '\r\n' and line and line[-1] == '\r':
450 if os.linesep == '\r\n' and line and line[-1] == '\r':
451 line = line[:-1]
451 line = line[:-1]
452 return line
452 return line
453
453
454 def prompt(self, msg, default="y"):
454 def prompt(self, msg, default="y"):
455 """Prompt user with msg, read response.
455 """Prompt user with msg, read response.
456 If ui is not interactive, the default is returned.
456 If ui is not interactive, the default is returned.
457 """
457 """
458 if not self.interactive():
458 if not self.interactive():
459 self.write(msg, ' ', default, "\n")
459 self.write(msg, ' ', default, "\n")
460 return default
460 return default
461 try:
461 try:
462 r = self._readline(msg + ' ')
462 r = self._readline(msg + ' ')
463 if not r:
463 if not r:
464 return default
464 return default
465 return r
465 return r
466 except EOFError:
466 except EOFError:
467 raise util.Abort(_('response expected'))
467 raise util.Abort(_('response expected'))
468
468
469 def promptchoice(self, msg, choices, default=0):
469 def promptchoice(self, msg, choices, default=0):
470 """Prompt user with msg, read response, and ensure it matches
470 """Prompt user with msg, read response, and ensure it matches
471 one of the provided choices. The index of the choice is returned.
471 one of the provided choices. The index of the choice is returned.
472 choices is a sequence of acceptable responses with the format:
472 choices is a sequence of acceptable responses with the format:
473 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
473 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
474 If ui is not interactive, the default is returned.
474 If ui is not interactive, the default is returned.
475 """
475 """
476 resps = [s[s.index('&')+1].lower() for s in choices]
476 resps = [s[s.index('&')+1].lower() for s in choices]
477 while True:
477 while True:
478 r = self.prompt(msg, resps[default])
478 r = self.prompt(msg, resps[default])
479 if r.lower() in resps:
479 if r.lower() in resps:
480 return resps.index(r.lower())
480 return resps.index(r.lower())
481 self.write(_("unrecognized response\n"))
481 self.write(_("unrecognized response\n"))
482
482
483 def getpass(self, prompt=None, default=None):
483 def getpass(self, prompt=None, default=None):
484 if not self.interactive():
484 if not self.interactive():
485 return default
485 return default
486 try:
486 try:
487 return getpass.getpass(prompt or _('password: '))
487 return getpass.getpass(prompt or _('password: '))
488 except EOFError:
488 except EOFError:
489 raise util.Abort(_('response expected'))
489 raise util.Abort(_('response expected'))
490 def status(self, *msg, **opts):
490 def status(self, *msg, **opts):
491 '''write status message to output (if ui.quiet is False)
491 '''write status message to output (if ui.quiet is False)
492
492
493 This adds an output label of "ui.status".
493 This adds an output label of "ui.status".
494 '''
494 '''
495 if not self.quiet:
495 if not self.quiet:
496 opts['label'] = opts.get('label', '') + ' ui.status'
496 opts['label'] = opts.get('label', '') + ' ui.status'
497 self.write(*msg, **opts)
497 self.write(*msg, **opts)
498 def warn(self, *msg, **opts):
498 def warn(self, *msg, **opts):
499 '''write warning message to output (stderr)
499 '''write warning message to output (stderr)
500
500
501 This adds an output label of "ui.warning".
501 This adds an output label of "ui.warning".
502 '''
502 '''
503 opts['label'] = opts.get('label', '') + ' ui.warning'
503 opts['label'] = opts.get('label', '') + ' ui.warning'
504 self.write_err(*msg, **opts)
504 self.write_err(*msg, **opts)
505 def note(self, *msg, **opts):
505 def note(self, *msg, **opts):
506 '''write note to output (if ui.verbose is True)
506 '''write note to output (if ui.verbose is True)
507
507
508 This adds an output label of "ui.note".
508 This adds an output label of "ui.note".
509 '''
509 '''
510 if self.verbose:
510 if self.verbose:
511 opts['label'] = opts.get('label', '') + ' ui.note'
511 opts['label'] = opts.get('label', '') + ' ui.note'
512 self.write(*msg, **opts)
512 self.write(*msg, **opts)
513 def debug(self, *msg, **opts):
513 def debug(self, *msg, **opts):
514 '''write debug message to output (if ui.debugflag is True)
514 '''write debug message to output (if ui.debugflag is True)
515
515
516 This adds an output label of "ui.debug".
516 This adds an output label of "ui.debug".
517 '''
517 '''
518 if self.debugflag:
518 if self.debugflag:
519 opts['label'] = opts.get('label', '') + ' ui.debug'
519 opts['label'] = opts.get('label', '') + ' ui.debug'
520 self.write(*msg, **opts)
520 self.write(*msg, **opts)
521 def edit(self, text, user):
521 def edit(self, text, user):
522 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
522 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
523 text=True)
523 text=True)
524 try:
524 try:
525 f = os.fdopen(fd, "w")
525 f = os.fdopen(fd, "w")
526 f.write(text)
526 f.write(text)
527 f.close()
527 f.close()
528
528
529 editor = self.geteditor()
529 editor = self.geteditor()
530
530
531 util.system("%s \"%s\"" % (editor, name),
531 util.system("%s \"%s\"" % (editor, name),
532 environ={'HGUSER': user},
532 environ={'HGUSER': user},
533 onerr=util.Abort, errprefix=_("edit failed"))
533 onerr=util.Abort, errprefix=_("edit failed"))
534
534
535 f = open(name)
535 f = open(name)
536 t = f.read()
536 t = f.read()
537 f.close()
537 f.close()
538 finally:
538 finally:
539 os.unlink(name)
539 os.unlink(name)
540
540
541 return t
541 return t
542
542
543 def traceback(self, exc=None):
543 def traceback(self, exc=None):
544 '''print exception traceback if traceback printing enabled.
544 '''print exception traceback if traceback printing enabled.
545 only to call in exception handler. returns true if traceback
545 only to call in exception handler. returns true if traceback
546 printed.'''
546 printed.'''
547 if self.tracebackflag:
547 if self.tracebackflag:
548 if exc:
548 if exc:
549 traceback.print_exception(exc[0], exc[1], exc[2])
549 traceback.print_exception(exc[0], exc[1], exc[2])
550 else:
550 else:
551 traceback.print_exc()
551 traceback.print_exc()
552 return self.tracebackflag
552 return self.tracebackflag
553
553
554 def geteditor(self):
554 def geteditor(self):
555 '''return editor to use'''
555 '''return editor to use'''
556 return (os.environ.get("HGEDITOR") or
556 return (os.environ.get("HGEDITOR") or
557 self.config("ui", "editor") or
557 self.config("ui", "editor") or
558 os.environ.get("VISUAL") or
558 os.environ.get("VISUAL") or
559 os.environ.get("EDITOR", "vi"))
559 os.environ.get("EDITOR", "vi"))
560
560
561 def progress(self, topic, pos, item="", unit="", total=None):
561 def progress(self, topic, pos, item="", unit="", total=None):
562 '''show a progress message
562 '''show a progress message
563
563
564 With stock hg, this is simply a debug message that is hidden
564 With stock hg, this is simply a debug message that is hidden
565 by default, but with extensions or GUI tools it may be
565 by default, but with extensions or GUI tools it may be
566 visible. 'topic' is the current operation, 'item' is a
566 visible. 'topic' is the current operation, 'item' is a
567 non-numeric marker of the current position (ie the currently
567 non-numeric marker of the current position (ie the currently
568 in-process file), 'pos' is the current numeric position (ie
568 in-process file), 'pos' is the current numeric position (ie
569 revision, bytes, etc.), unit is a corresponding unit label,
569 revision, bytes, etc.), unit is a corresponding unit label,
570 and total is the highest expected pos.
570 and total is the highest expected pos.
571
571
572 Multiple nested topics may be active at a time.
572 Multiple nested topics may be active at a time.
573
573
574 All topics should be marked closed by setting pos to None at
574 All topics should be marked closed by setting pos to None at
575 termination.
575 termination.
576 '''
576 '''
577
577
578 if pos == None or not self.debugflag:
578 if pos == None or not self.debugflag:
579 return
579 return
580
580
581 if unit:
581 if unit:
582 unit = ' ' + unit
582 unit = ' ' + unit
583 if item:
583 if item:
584 item = ' ' + item
584 item = ' ' + item
585
585
586 if total:
586 if total:
587 pct = 100.0 * pos / total
587 pct = 100.0 * pos / total
588 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
588 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
589 % (topic, item, pos, total, unit, pct))
589 % (topic, item, pos, total, unit, pct))
590 else:
590 else:
591 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
591 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
592
592
593 def log(self, service, message):
593 def log(self, service, message):
594 '''hook for logging facility extensions
594 '''hook for logging facility extensions
595
595
596 service should be a readily-identifiable subsystem, which will
596 service should be a readily-identifiable subsystem, which will
597 allow filtering.
597 allow filtering.
598 message should be a newline-terminated string to log.
598 message should be a newline-terminated string to log.
599 '''
599 '''
600 pass
600 pass
601
601
602 def label(self, msg, label):
602 def label(self, msg, label):
603 '''style msg based on supplied label
603 '''style msg based on supplied label
604
604
605 Like ui.write(), this just returns msg unchanged, but extensions
605 Like ui.write(), this just returns msg unchanged, but extensions
606 and GUI tools can override it to allow styling output without
606 and GUI tools can override it to allow styling output without
607 writing it.
607 writing it.
608
608
609 ui.write(s, 'label') is equivalent to
609 ui.write(s, 'label') is equivalent to
610 ui.write(ui.label(s, 'label')).
610 ui.write(ui.label(s, 'label')).
611 '''
611 '''
612 return msg
612 return msg
General Comments 0
You need to be logged in to leave comments. Login now