##// END OF EJS Templates
ui: move _isatty near user
Matt Mackall -
r8132:cece135f default
parent child Browse files
Show More
@@ -1,490 +1,489 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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, re, socket, sys, tempfile
9 import errno, getpass, os, re, socket, sys, tempfile
10 import ConfigParser, traceback, util
10 import ConfigParser, traceback, util
11
11
12 def dupconfig(orig):
12 def dupconfig(orig):
13 new = util.configparser(orig.defaults())
13 new = util.configparser(orig.defaults())
14 updateconfig(orig, new)
14 updateconfig(orig, new)
15 return new
15 return new
16
16
17 def updateconfig(source, dest, sections=None):
17 def updateconfig(source, dest, sections=None):
18 if not sections:
18 if not sections:
19 sections = source.sections()
19 sections = source.sections()
20 for section in sections:
20 for section in sections:
21 if not dest.has_section(section):
21 if not dest.has_section(section):
22 dest.add_section(section)
22 dest.add_section(section)
23 for name, value in source.items(section, raw=True):
23 for name, value in source.items(section, raw=True):
24 dest.set(section, name, value)
24 dest.set(section, name, value)
25
25
26 class ui(object):
26 class ui(object):
27 _isatty = None
28
29 def __init__(self, verbose=False, debug=False, quiet=False,
27 def __init__(self, verbose=False, debug=False, quiet=False,
30 interactive=True, traceback=False, report_untrusted=True,
28 interactive=True, traceback=False, report_untrusted=True,
31 parentui=None):
29 parentui=None):
32 self.overlay = None
30 self.overlay = None
33 self.buffers = []
31 self.buffers = []
34 if parentui is None:
32 if parentui is None:
35 # this is the parent of all ui children
33 # this is the parent of all ui children
36 self.parentui = None
34 self.parentui = None
37 self.quiet = quiet
35 self.quiet = quiet
38 self.verbose = verbose
36 self.verbose = verbose
39 self.debugflag = debug
37 self.debugflag = debug
40 self.interactive = interactive
38 self.interactive = interactive
41 self.traceback = traceback
39 self.traceback = traceback
42 self.report_untrusted = report_untrusted
40 self.report_untrusted = report_untrusted
43 self.trusted_users = {}
41 self.trusted_users = {}
44 self.trusted_groups = {}
42 self.trusted_groups = {}
45 # if ucdata is not None, its keys must be a superset of cdata's
43 # if ucdata is not None, its keys must be a superset of cdata's
46 self.cdata = util.configparser()
44 self.cdata = util.configparser()
47 self.ucdata = None
45 self.ucdata = None
48 # we always trust global config files
46 # we always trust global config files
49 self.check_trusted = False
47 self.check_trusted = False
50 self.readconfig(util.rcpath())
48 self.readconfig(util.rcpath())
51 self.check_trusted = True
49 self.check_trusted = True
52 self.updateopts(verbose, debug, quiet, interactive)
50 self.updateopts(verbose, debug, quiet, interactive)
53 else:
51 else:
54 # parentui may point to an ui object which is already a child
52 # parentui may point to an ui object which is already a child
55 self.parentui = parentui.parentui or parentui
53 self.parentui = parentui.parentui or parentui
56 self.trusted_users = parentui.trusted_users.copy()
54 self.trusted_users = parentui.trusted_users.copy()
57 self.trusted_groups = parentui.trusted_groups.copy()
55 self.trusted_groups = parentui.trusted_groups.copy()
58 self.cdata = dupconfig(self.parentui.cdata)
56 self.cdata = dupconfig(self.parentui.cdata)
59 if self.parentui.ucdata:
57 if self.parentui.ucdata:
60 self.ucdata = dupconfig(self.parentui.ucdata)
58 self.ucdata = dupconfig(self.parentui.ucdata)
61 if self.parentui.overlay:
59 if self.parentui.overlay:
62 self.overlay = dupconfig(self.parentui.overlay)
60 self.overlay = dupconfig(self.parentui.overlay)
63 if self.parentui is not parentui and parentui.overlay is not None:
61 if self.parentui is not parentui and parentui.overlay is not None:
64 if self.overlay is None:
62 if self.overlay is None:
65 self.overlay = util.configparser()
63 self.overlay = util.configparser()
66 updateconfig(parentui.overlay, self.overlay)
64 updateconfig(parentui.overlay, self.overlay)
67 self.buffers = parentui.buffers
65 self.buffers = parentui.buffers
68
66
69 def __getattr__(self, key):
67 def __getattr__(self, key):
70 return getattr(self.parentui, key)
68 return getattr(self.parentui, key)
71
69
70 _isatty = None
72 def isatty(self):
71 def isatty(self):
73 if ui._isatty is None:
72 if ui._isatty is None:
74 ui._isatty = sys.stdin.isatty()
73 ui._isatty = sys.stdin.isatty()
75 return ui._isatty
74 return ui._isatty
76
75
77 def updateopts(self, verbose=False, debug=False, quiet=False,
76 def updateopts(self, verbose=False, debug=False, quiet=False,
78 interactive=True, traceback=False, config=[]):
77 interactive=True, traceback=False, config=[]):
79 for section, name, value in config:
78 for section, name, value in config:
80 self.setconfig(section, name, value)
79 self.setconfig(section, name, value)
81
80
82 if quiet or verbose or debug:
81 if quiet or verbose or debug:
83 self.setconfig('ui', 'quiet', str(bool(quiet)))
82 self.setconfig('ui', 'quiet', str(bool(quiet)))
84 self.setconfig('ui', 'verbose', str(bool(verbose)))
83 self.setconfig('ui', 'verbose', str(bool(verbose)))
85 self.setconfig('ui', 'debug', str(bool(debug)))
84 self.setconfig('ui', 'debug', str(bool(debug)))
86
85
87 self.verbosity_constraints()
86 self.verbosity_constraints()
88
87
89 if not interactive:
88 if not interactive:
90 self.setconfig('ui', 'interactive', 'False')
89 self.setconfig('ui', 'interactive', 'False')
91 self.interactive = False
90 self.interactive = False
92
91
93 self.traceback = self.traceback or traceback
92 self.traceback = self.traceback or traceback
94
93
95 def verbosity_constraints(self):
94 def verbosity_constraints(self):
96 self.quiet = self.configbool('ui', 'quiet')
95 self.quiet = self.configbool('ui', 'quiet')
97 self.verbose = self.configbool('ui', 'verbose')
96 self.verbose = self.configbool('ui', 'verbose')
98 self.debugflag = self.configbool('ui', 'debug')
97 self.debugflag = self.configbool('ui', 'debug')
99
98
100 if self.debugflag:
99 if self.debugflag:
101 self.verbose = True
100 self.verbose = True
102 self.quiet = False
101 self.quiet = False
103 elif self.verbose and self.quiet:
102 elif self.verbose and self.quiet:
104 self.quiet = self.verbose = False
103 self.quiet = self.verbose = False
105
104
106 def _is_trusted(self, fp, f, warn=True):
105 def _is_trusted(self, fp, f, warn=True):
107 if not self.check_trusted:
106 if not self.check_trusted:
108 return True
107 return True
109 st = util.fstat(fp)
108 st = util.fstat(fp)
110 if util.isowner(fp, st):
109 if util.isowner(fp, st):
111 return True
110 return True
112 tusers = self.trusted_users
111 tusers = self.trusted_users
113 tgroups = self.trusted_groups
112 tgroups = self.trusted_groups
114 if not tusers:
113 if not tusers:
115 user = util.username()
114 user = util.username()
116 if user is not None:
115 if user is not None:
117 self.trusted_users[user] = 1
116 self.trusted_users[user] = 1
118 self.fixconfig(section='trusted')
117 self.fixconfig(section='trusted')
119 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
118 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
120 user = util.username(st.st_uid)
119 user = util.username(st.st_uid)
121 group = util.groupname(st.st_gid)
120 group = util.groupname(st.st_gid)
122 if user not in tusers and group not in tgroups:
121 if user not in tusers and group not in tgroups:
123 if warn and self.report_untrusted:
122 if warn and self.report_untrusted:
124 self.warn(_('Not trusting file %s from untrusted '
123 self.warn(_('Not trusting file %s from untrusted '
125 'user %s, group %s\n') % (f, user, group))
124 'user %s, group %s\n') % (f, user, group))
126 return False
125 return False
127 return True
126 return True
128
127
129 def readconfig(self, fn, root=None):
128 def readconfig(self, fn, root=None):
130 if isinstance(fn, basestring):
129 if isinstance(fn, basestring):
131 fn = [fn]
130 fn = [fn]
132 for f in fn:
131 for f in fn:
133 try:
132 try:
134 fp = open(f)
133 fp = open(f)
135 except IOError:
134 except IOError:
136 continue
135 continue
137 cdata = self.cdata
136 cdata = self.cdata
138 trusted = self._is_trusted(fp, f)
137 trusted = self._is_trusted(fp, f)
139 if not trusted:
138 if not trusted:
140 if self.ucdata is None:
139 if self.ucdata is None:
141 self.ucdata = dupconfig(self.cdata)
140 self.ucdata = dupconfig(self.cdata)
142 cdata = self.ucdata
141 cdata = self.ucdata
143 elif self.ucdata is not None:
142 elif self.ucdata is not None:
144 # use a separate configparser, so that we don't accidentally
143 # use a separate configparser, so that we don't accidentally
145 # override ucdata settings later on.
144 # override ucdata settings later on.
146 cdata = util.configparser()
145 cdata = util.configparser()
147
146
148 try:
147 try:
149 cdata.readfp(fp, f)
148 cdata.readfp(fp, f)
150 except ConfigParser.ParsingError, inst:
149 except ConfigParser.ParsingError, inst:
151 msg = _("Failed to parse %s\n%s") % (f, inst)
150 msg = _("Failed to parse %s\n%s") % (f, inst)
152 if trusted:
151 if trusted:
153 raise util.Abort(msg)
152 raise util.Abort(msg)
154 self.warn(_("Ignored: %s\n") % msg)
153 self.warn(_("Ignored: %s\n") % msg)
155
154
156 if trusted:
155 if trusted:
157 if cdata != self.cdata:
156 if cdata != self.cdata:
158 updateconfig(cdata, self.cdata)
157 updateconfig(cdata, self.cdata)
159 if self.ucdata is not None:
158 if self.ucdata is not None:
160 updateconfig(cdata, self.ucdata)
159 updateconfig(cdata, self.ucdata)
161 # override data from config files with data set with ui.setconfig
160 # override data from config files with data set with ui.setconfig
162 if self.overlay:
161 if self.overlay:
163 updateconfig(self.overlay, self.cdata)
162 updateconfig(self.overlay, self.cdata)
164 if root is None:
163 if root is None:
165 root = os.path.expanduser('~')
164 root = os.path.expanduser('~')
166 self.fixconfig(root=root)
165 self.fixconfig(root=root)
167
166
168 def readsections(self, filename, *sections):
167 def readsections(self, filename, *sections):
169 """Read filename and add only the specified sections to the config data
168 """Read filename and add only the specified sections to the config data
170
169
171 The settings are added to the trusted config data.
170 The settings are added to the trusted config data.
172 """
171 """
173 if not sections:
172 if not sections:
174 return
173 return
175
174
176 cdata = util.configparser()
175 cdata = util.configparser()
177 try:
176 try:
178 try:
177 try:
179 fp = open(filename)
178 fp = open(filename)
180 except IOError, inst:
179 except IOError, inst:
181 raise util.Abort(_("unable to open %s: %s") %
180 raise util.Abort(_("unable to open %s: %s") %
182 (filename, getattr(inst, "strerror", inst)))
181 (filename, getattr(inst, "strerror", inst)))
183 try:
182 try:
184 cdata.readfp(fp, filename)
183 cdata.readfp(fp, filename)
185 finally:
184 finally:
186 fp.close()
185 fp.close()
187 except ConfigParser.ParsingError, inst:
186 except ConfigParser.ParsingError, inst:
188 raise util.Abort(_("failed to parse %s\n%s") % (filename, inst))
187 raise util.Abort(_("failed to parse %s\n%s") % (filename, inst))
189
188
190 for section in sections:
189 for section in sections:
191 if not cdata.has_section(section):
190 if not cdata.has_section(section):
192 cdata.add_section(section)
191 cdata.add_section(section)
193
192
194 updateconfig(cdata, self.cdata, sections)
193 updateconfig(cdata, self.cdata, sections)
195 if self.ucdata:
194 if self.ucdata:
196 updateconfig(cdata, self.ucdata, sections)
195 updateconfig(cdata, self.ucdata, sections)
197
196
198 def fixconfig(self, section=None, name=None, value=None, root=None):
197 def fixconfig(self, section=None, name=None, value=None, root=None):
199 # translate paths relative to root (or home) into absolute paths
198 # translate paths relative to root (or home) into absolute paths
200 if section is None or section == 'paths':
199 if section is None or section == 'paths':
201 if root is None:
200 if root is None:
202 root = os.getcwd()
201 root = os.getcwd()
203 items = section and [(name, value)] or []
202 items = section and [(name, value)] or []
204 for cdata in self.cdata, self.ucdata, self.overlay:
203 for cdata in self.cdata, self.ucdata, self.overlay:
205 if not cdata: continue
204 if not cdata: continue
206 if not items and cdata.has_section('paths'):
205 if not items and cdata.has_section('paths'):
207 pathsitems = cdata.items('paths')
206 pathsitems = cdata.items('paths')
208 else:
207 else:
209 pathsitems = items
208 pathsitems = items
210 for n, path in pathsitems:
209 for n, path in pathsitems:
211 if path and "://" not in path and not os.path.isabs(path):
210 if path and "://" not in path and not os.path.isabs(path):
212 cdata.set("paths", n,
211 cdata.set("paths", n,
213 os.path.normpath(os.path.join(root, path)))
212 os.path.normpath(os.path.join(root, path)))
214
213
215 # update verbosity/interactive/report_untrusted settings
214 # update verbosity/interactive/report_untrusted settings
216 if section is None or section == 'ui':
215 if section is None or section == 'ui':
217 if name is None or name in ('quiet', 'verbose', 'debug'):
216 if name is None or name in ('quiet', 'verbose', 'debug'):
218 self.verbosity_constraints()
217 self.verbosity_constraints()
219 if name is None or name == 'interactive':
218 if name is None or name == 'interactive':
220 interactive = self.configbool("ui", "interactive", None)
219 interactive = self.configbool("ui", "interactive", None)
221 if interactive is None and self.interactive:
220 if interactive is None and self.interactive:
222 self.interactive = self.isatty()
221 self.interactive = self.isatty()
223 else:
222 else:
224 self.interactive = interactive
223 self.interactive = interactive
225 if name is None or name == 'report_untrusted':
224 if name is None or name == 'report_untrusted':
226 self.report_untrusted = (
225 self.report_untrusted = (
227 self.configbool("ui", "report_untrusted", True))
226 self.configbool("ui", "report_untrusted", True))
228
227
229 # update trust information
228 # update trust information
230 if (section is None or section == 'trusted') and self.trusted_users:
229 if (section is None or section == 'trusted') and self.trusted_users:
231 for user in self.configlist('trusted', 'users'):
230 for user in self.configlist('trusted', 'users'):
232 self.trusted_users[user] = 1
231 self.trusted_users[user] = 1
233 for group in self.configlist('trusted', 'groups'):
232 for group in self.configlist('trusted', 'groups'):
234 self.trusted_groups[group] = 1
233 self.trusted_groups[group] = 1
235
234
236 def setconfig(self, section, name, value):
235 def setconfig(self, section, name, value):
237 if not self.overlay:
236 if not self.overlay:
238 self.overlay = util.configparser()
237 self.overlay = util.configparser()
239 for cdata in (self.overlay, self.cdata, self.ucdata):
238 for cdata in (self.overlay, self.cdata, self.ucdata):
240 if not cdata: continue
239 if not cdata: continue
241 if not cdata.has_section(section):
240 if not cdata.has_section(section):
242 cdata.add_section(section)
241 cdata.add_section(section)
243 cdata.set(section, name, value)
242 cdata.set(section, name, value)
244 self.fixconfig(section, name, value)
243 self.fixconfig(section, name, value)
245
244
246 def _get_cdata(self, untrusted):
245 def _get_cdata(self, untrusted):
247 if untrusted and self.ucdata:
246 if untrusted and self.ucdata:
248 return self.ucdata
247 return self.ucdata
249 return self.cdata
248 return self.cdata
250
249
251 def _config(self, section, name, default, funcname, untrusted, abort):
250 def _config(self, section, name, default, funcname, untrusted, abort):
252 cdata = self._get_cdata(untrusted)
251 cdata = self._get_cdata(untrusted)
253 if cdata.has_option(section, name):
252 if cdata.has_option(section, name):
254 try:
253 try:
255 func = getattr(cdata, funcname)
254 func = getattr(cdata, funcname)
256 return func(section, name)
255 return func(section, name)
257 except (ConfigParser.InterpolationError, ValueError), inst:
256 except (ConfigParser.InterpolationError, ValueError), inst:
258 msg = _("Error in configuration section [%s] "
257 msg = _("Error in configuration section [%s] "
259 "parameter '%s':\n%s") % (section, name, inst)
258 "parameter '%s':\n%s") % (section, name, inst)
260 if abort:
259 if abort:
261 raise util.Abort(msg)
260 raise util.Abort(msg)
262 self.warn(_("Ignored: %s\n") % msg)
261 self.warn(_("Ignored: %s\n") % msg)
263 return default
262 return default
264
263
265 def _configcommon(self, section, name, default, funcname, untrusted):
264 def _configcommon(self, section, name, default, funcname, untrusted):
266 value = self._config(section, name, default, funcname,
265 value = self._config(section, name, default, funcname,
267 untrusted, abort=True)
266 untrusted, abort=True)
268 if self.debugflag and not untrusted and self.ucdata:
267 if self.debugflag and not untrusted and self.ucdata:
269 uvalue = self._config(section, name, None, funcname,
268 uvalue = self._config(section, name, None, funcname,
270 untrusted=True, abort=False)
269 untrusted=True, abort=False)
271 if uvalue is not None and uvalue != value:
270 if uvalue is not None and uvalue != value:
272 self.warn(_("Ignoring untrusted configuration option "
271 self.warn(_("Ignoring untrusted configuration option "
273 "%s.%s = %s\n") % (section, name, uvalue))
272 "%s.%s = %s\n") % (section, name, uvalue))
274 return value
273 return value
275
274
276 def config(self, section, name, default=None, untrusted=False):
275 def config(self, section, name, default=None, untrusted=False):
277 return self._configcommon(section, name, default, 'get', untrusted)
276 return self._configcommon(section, name, default, 'get', untrusted)
278
277
279 def configbool(self, section, name, default=False, untrusted=False):
278 def configbool(self, section, name, default=False, untrusted=False):
280 return self._configcommon(section, name, default, 'getboolean',
279 return self._configcommon(section, name, default, 'getboolean',
281 untrusted)
280 untrusted)
282
281
283 def configlist(self, section, name, default=None, untrusted=False):
282 def configlist(self, section, name, default=None, untrusted=False):
284 """Return a list of comma/space separated strings"""
283 """Return a list of comma/space separated strings"""
285 result = self.config(section, name, untrusted=untrusted)
284 result = self.config(section, name, untrusted=untrusted)
286 if result is None:
285 if result is None:
287 result = default or []
286 result = default or []
288 if isinstance(result, basestring):
287 if isinstance(result, basestring):
289 result = result.replace(",", " ").split()
288 result = result.replace(",", " ").split()
290 return result
289 return result
291
290
292 def has_section(self, section, untrusted=False):
291 def has_section(self, section, untrusted=False):
293 '''tell whether section exists in config.'''
292 '''tell whether section exists in config.'''
294 cdata = self._get_cdata(untrusted)
293 cdata = self._get_cdata(untrusted)
295 return cdata.has_section(section)
294 return cdata.has_section(section)
296
295
297 def _configitems(self, section, untrusted, abort):
296 def _configitems(self, section, untrusted, abort):
298 items = {}
297 items = {}
299 cdata = self._get_cdata(untrusted)
298 cdata = self._get_cdata(untrusted)
300 if cdata.has_section(section):
299 if cdata.has_section(section):
301 try:
300 try:
302 items.update(dict(cdata.items(section)))
301 items.update(dict(cdata.items(section)))
303 except ConfigParser.InterpolationError, inst:
302 except ConfigParser.InterpolationError, inst:
304 msg = _("Error in configuration section [%s]:\n"
303 msg = _("Error in configuration section [%s]:\n"
305 "%s") % (section, inst)
304 "%s") % (section, inst)
306 if abort:
305 if abort:
307 raise util.Abort(msg)
306 raise util.Abort(msg)
308 self.warn(_("Ignored: %s\n") % msg)
307 self.warn(_("Ignored: %s\n") % msg)
309 return items
308 return items
310
309
311 def configitems(self, section, untrusted=False):
310 def configitems(self, section, untrusted=False):
312 items = self._configitems(section, untrusted=untrusted, abort=True)
311 items = self._configitems(section, untrusted=untrusted, abort=True)
313 if self.debugflag and not untrusted and self.ucdata:
312 if self.debugflag and not untrusted and self.ucdata:
314 uitems = self._configitems(section, untrusted=True, abort=False)
313 uitems = self._configitems(section, untrusted=True, abort=False)
315 for k in util.sort(uitems):
314 for k in util.sort(uitems):
316 if uitems[k] != items.get(k):
315 if uitems[k] != items.get(k):
317 self.warn(_("Ignoring untrusted configuration option "
316 self.warn(_("Ignoring untrusted configuration option "
318 "%s.%s = %s\n") % (section, k, uitems[k]))
317 "%s.%s = %s\n") % (section, k, uitems[k]))
319 return util.sort(items.items())
318 return util.sort(items.items())
320
319
321 def walkconfig(self, untrusted=False):
320 def walkconfig(self, untrusted=False):
322 cdata = self._get_cdata(untrusted)
321 cdata = self._get_cdata(untrusted)
323 sections = cdata.sections()
322 sections = cdata.sections()
324 sections.sort()
323 sections.sort()
325 for section in sections:
324 for section in sections:
326 for name, value in self.configitems(section, untrusted):
325 for name, value in self.configitems(section, untrusted):
327 yield section, name, str(value).replace('\n', '\\n')
326 yield section, name, str(value).replace('\n', '\\n')
328
327
329 def username(self):
328 def username(self):
330 """Return default username to be used in commits.
329 """Return default username to be used in commits.
331
330
332 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
331 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
333 and stop searching if one of these is set.
332 and stop searching if one of these is set.
334 If not found and ui.askusername is True, ask the user, else use
333 If not found and ui.askusername is True, ask the user, else use
335 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
334 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
336 """
335 """
337 user = os.environ.get("HGUSER")
336 user = os.environ.get("HGUSER")
338 if user is None:
337 if user is None:
339 user = self.config("ui", "username")
338 user = self.config("ui", "username")
340 if user is None:
339 if user is None:
341 user = os.environ.get("EMAIL")
340 user = os.environ.get("EMAIL")
342 if user is None and self.configbool("ui", "askusername"):
341 if user is None and self.configbool("ui", "askusername"):
343 user = self.prompt(_("enter a commit username:"), default=None)
342 user = self.prompt(_("enter a commit username:"), default=None)
344 if user is None:
343 if user is None:
345 try:
344 try:
346 user = '%s@%s' % (util.getuser(), socket.getfqdn())
345 user = '%s@%s' % (util.getuser(), socket.getfqdn())
347 self.warn(_("No username found, using '%s' instead\n") % user)
346 self.warn(_("No username found, using '%s' instead\n") % user)
348 except KeyError:
347 except KeyError:
349 pass
348 pass
350 if not user:
349 if not user:
351 raise util.Abort(_("Please specify a username."))
350 raise util.Abort(_("Please specify a username."))
352 if "\n" in user:
351 if "\n" in user:
353 raise util.Abort(_("username %s contains a newline\n") % repr(user))
352 raise util.Abort(_("username %s contains a newline\n") % repr(user))
354 return user
353 return user
355
354
356 def shortuser(self, user):
355 def shortuser(self, user):
357 """Return a short representation of a user name or email address."""
356 """Return a short representation of a user name or email address."""
358 if not self.verbose: user = util.shortuser(user)
357 if not self.verbose: user = util.shortuser(user)
359 return user
358 return user
360
359
361 def expandpath(self, loc, default=None):
360 def expandpath(self, loc, default=None):
362 """Return repository location relative to cwd or from [paths]"""
361 """Return repository location relative to cwd or from [paths]"""
363 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
362 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
364 return loc
363 return loc
365
364
366 path = self.config("paths", loc)
365 path = self.config("paths", loc)
367 if not path and default is not None:
366 if not path and default is not None:
368 path = self.config("paths", default)
367 path = self.config("paths", default)
369 return path or loc
368 return path or loc
370
369
371 def pushbuffer(self):
370 def pushbuffer(self):
372 self.buffers.append([])
371 self.buffers.append([])
373
372
374 def popbuffer(self):
373 def popbuffer(self):
375 return "".join(self.buffers.pop())
374 return "".join(self.buffers.pop())
376
375
377 def write(self, *args):
376 def write(self, *args):
378 if self.buffers:
377 if self.buffers:
379 self.buffers[-1].extend([str(a) for a in args])
378 self.buffers[-1].extend([str(a) for a in args])
380 else:
379 else:
381 for a in args:
380 for a in args:
382 sys.stdout.write(str(a))
381 sys.stdout.write(str(a))
383
382
384 def write_err(self, *args):
383 def write_err(self, *args):
385 try:
384 try:
386 if not sys.stdout.closed: sys.stdout.flush()
385 if not sys.stdout.closed: sys.stdout.flush()
387 for a in args:
386 for a in args:
388 sys.stderr.write(str(a))
387 sys.stderr.write(str(a))
389 # stderr may be buffered under win32 when redirected to files,
388 # stderr may be buffered under win32 when redirected to files,
390 # including stdout.
389 # including stdout.
391 if not sys.stderr.closed: sys.stderr.flush()
390 if not sys.stderr.closed: sys.stderr.flush()
392 except IOError, inst:
391 except IOError, inst:
393 if inst.errno != errno.EPIPE:
392 if inst.errno != errno.EPIPE:
394 raise
393 raise
395
394
396 def flush(self):
395 def flush(self):
397 try: sys.stdout.flush()
396 try: sys.stdout.flush()
398 except: pass
397 except: pass
399 try: sys.stderr.flush()
398 try: sys.stderr.flush()
400 except: pass
399 except: pass
401
400
402 def _readline(self, prompt=''):
401 def _readline(self, prompt=''):
403 if self.isatty():
402 if self.isatty():
404 try:
403 try:
405 # magically add command line editing support, where
404 # magically add command line editing support, where
406 # available
405 # available
407 import readline
406 import readline
408 # force demandimport to really load the module
407 # force demandimport to really load the module
409 readline.read_history_file
408 readline.read_history_file
410 # windows sometimes raises something other than ImportError
409 # windows sometimes raises something other than ImportError
411 except Exception:
410 except Exception:
412 pass
411 pass
413 line = raw_input(prompt)
412 line = raw_input(prompt)
414 # When stdin is in binary mode on Windows, it can cause
413 # When stdin is in binary mode on Windows, it can cause
415 # raw_input() to emit an extra trailing carriage return
414 # raw_input() to emit an extra trailing carriage return
416 if os.linesep == '\r\n' and line and line[-1] == '\r':
415 if os.linesep == '\r\n' and line and line[-1] == '\r':
417 line = line[:-1]
416 line = line[:-1]
418 return line
417 return line
419
418
420 def prompt(self, msg, pat=None, default="y"):
419 def prompt(self, msg, pat=None, default="y"):
421 """Prompt user with msg, read response, and ensure it matches pat
420 """Prompt user with msg, read response, and ensure it matches pat
422
421
423 If not interactive -- the default is returned
422 If not interactive -- the default is returned
424 """
423 """
425 if not self.interactive:
424 if not self.interactive:
426 self.note(msg, ' ', default, "\n")
425 self.note(msg, ' ', default, "\n")
427 return default
426 return default
428 while True:
427 while True:
429 try:
428 try:
430 r = self._readline(msg + ' ')
429 r = self._readline(msg + ' ')
431 if not r:
430 if not r:
432 return default
431 return default
433 if not pat or re.match(pat, r):
432 if not pat or re.match(pat, r):
434 return r
433 return r
435 else:
434 else:
436 self.write(_("unrecognized response\n"))
435 self.write(_("unrecognized response\n"))
437 except EOFError:
436 except EOFError:
438 raise util.Abort(_('response expected'))
437 raise util.Abort(_('response expected'))
439
438
440 def getpass(self, prompt=None, default=None):
439 def getpass(self, prompt=None, default=None):
441 if not self.interactive: return default
440 if not self.interactive: return default
442 try:
441 try:
443 return getpass.getpass(prompt or _('password: '))
442 return getpass.getpass(prompt or _('password: '))
444 except EOFError:
443 except EOFError:
445 raise util.Abort(_('response expected'))
444 raise util.Abort(_('response expected'))
446 def status(self, *msg):
445 def status(self, *msg):
447 if not self.quiet: self.write(*msg)
446 if not self.quiet: self.write(*msg)
448 def warn(self, *msg):
447 def warn(self, *msg):
449 self.write_err(*msg)
448 self.write_err(*msg)
450 def note(self, *msg):
449 def note(self, *msg):
451 if self.verbose: self.write(*msg)
450 if self.verbose: self.write(*msg)
452 def debug(self, *msg):
451 def debug(self, *msg):
453 if self.debugflag: self.write(*msg)
452 if self.debugflag: self.write(*msg)
454 def edit(self, text, user):
453 def edit(self, text, user):
455 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
454 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
456 text=True)
455 text=True)
457 try:
456 try:
458 f = os.fdopen(fd, "w")
457 f = os.fdopen(fd, "w")
459 f.write(text)
458 f.write(text)
460 f.close()
459 f.close()
461
460
462 editor = self.geteditor()
461 editor = self.geteditor()
463
462
464 util.system("%s \"%s\"" % (editor, name),
463 util.system("%s \"%s\"" % (editor, name),
465 environ={'HGUSER': user},
464 environ={'HGUSER': user},
466 onerr=util.Abort, errprefix=_("edit failed"))
465 onerr=util.Abort, errprefix=_("edit failed"))
467
466
468 f = open(name)
467 f = open(name)
469 t = f.read()
468 t = f.read()
470 f.close()
469 f.close()
471 t = re.sub("(?m)^HG:.*\n", "", t)
470 t = re.sub("(?m)^HG:.*\n", "", t)
472 finally:
471 finally:
473 os.unlink(name)
472 os.unlink(name)
474
473
475 return t
474 return t
476
475
477 def print_exc(self):
476 def print_exc(self):
478 '''print exception traceback if traceback printing enabled.
477 '''print exception traceback if traceback printing enabled.
479 only to call in exception handler. returns true if traceback
478 only to call in exception handler. returns true if traceback
480 printed.'''
479 printed.'''
481 if self.traceback:
480 if self.traceback:
482 traceback.print_exc()
481 traceback.print_exc()
483 return self.traceback
482 return self.traceback
484
483
485 def geteditor(self):
484 def geteditor(self):
486 '''return editor to use'''
485 '''return editor to use'''
487 return (os.environ.get("HGEDITOR") or
486 return (os.environ.get("HGEDITOR") or
488 self.config("ui", "editor") or
487 self.config("ui", "editor") or
489 os.environ.get("VISUAL") or
488 os.environ.get("VISUAL") or
490 os.environ.get("EDITOR", "vi"))
489 os.environ.get("EDITOR", "vi"))
General Comments 0
You need to be logged in to leave comments. Login now