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