##// END OF EJS Templates
improve code readability
Andrey Somov -
r9436:96379c93 default
parent child Browse files
Show More
@@ -1,509 +1,509 b''
1 1 # dispatch.py - command dispatching 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 of the
6 6 # GNU General Public License version 2, incorporated herein by reference.
7 7
8 8 from i18n import _
9 9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time
10 10 import util, commands, hg, fancyopts, extensions, hook, error
11 11 import cmdutil, encoding
12 12 import ui as _ui
13 13
14 14 def run():
15 15 "run the command in sys.argv"
16 16 sys.exit(dispatch(sys.argv[1:]))
17 17
18 18 def dispatch(args):
19 19 "run the command specified in args"
20 20 try:
21 21 u = _ui.ui()
22 22 if '--traceback' in args:
23 23 u.setconfig('ui', 'traceback', 'on')
24 24 except util.Abort, inst:
25 25 sys.stderr.write(_("abort: %s\n") % inst)
26 26 return -1
27 27 return _runcatch(u, args)
28 28
29 29 def _runcatch(ui, args):
30 30 def catchterm(*args):
31 31 raise error.SignalInterrupt
32 32
33 33 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
34 34 num = getattr(signal, name, None)
35 35 if num: signal.signal(num, catchterm)
36 36
37 37 try:
38 38 try:
39 39 # enter the debugger before command execution
40 40 if '--debugger' in args:
41 41 pdb.set_trace()
42 42 try:
43 43 return _dispatch(ui, args)
44 44 finally:
45 45 ui.flush()
46 46 except:
47 47 # enter the debugger when we hit an exception
48 48 if '--debugger' in args:
49 49 pdb.post_mortem(sys.exc_info()[2])
50 50 ui.traceback()
51 51 raise
52 52
53 53 # Global exception handling, alphabetically
54 54 # Mercurial-specific first, followed by built-in and library exceptions
55 55 except error.AmbiguousCommand, inst:
56 56 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
57 57 (inst.args[0], " ".join(inst.args[1])))
58 58 except error.ConfigError, inst:
59 59 ui.warn(_("hg: %s\n") % inst.args[0])
60 60 except error.LockHeld, inst:
61 61 if inst.errno == errno.ETIMEDOUT:
62 62 reason = _('timed out waiting for lock held by %s') % inst.locker
63 63 else:
64 64 reason = _('lock held by %s') % inst.locker
65 65 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
66 66 except error.LockUnavailable, inst:
67 67 ui.warn(_("abort: could not lock %s: %s\n") %
68 68 (inst.desc or inst.filename, inst.strerror))
69 69 except error.ParseError, inst:
70 70 if inst.args[0]:
71 71 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
72 72 commands.help_(ui, inst.args[0])
73 73 else:
74 74 ui.warn(_("hg: %s\n") % inst.args[1])
75 75 commands.help_(ui, 'shortlist')
76 76 except error.RepoError, inst:
77 77 ui.warn(_("abort: %s!\n") % inst)
78 78 except error.ResponseError, inst:
79 79 ui.warn(_("abort: %s") % inst.args[0])
80 80 if not isinstance(inst.args[1], basestring):
81 81 ui.warn(" %r\n" % (inst.args[1],))
82 82 elif not inst.args[1]:
83 83 ui.warn(_(" empty string\n"))
84 84 else:
85 85 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
86 86 except error.RevlogError, inst:
87 87 ui.warn(_("abort: %s!\n") % inst)
88 88 except error.SignalInterrupt:
89 89 ui.warn(_("killed!\n"))
90 90 except error.UnknownCommand, inst:
91 91 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
92 92 commands.help_(ui, 'shortlist')
93 93 except util.Abort, inst:
94 94 ui.warn(_("abort: %s\n") % inst)
95 95 except ImportError, inst:
96 96 m = str(inst).split()[-1]
97 97 ui.warn(_("abort: could not import module %s!\n") % m)
98 98 if m in "mpatch bdiff".split():
99 99 ui.warn(_("(did you forget to compile extensions?)\n"))
100 100 elif m in "zlib".split():
101 101 ui.warn(_("(is your Python install correct?)\n"))
102 102 except IOError, inst:
103 103 if hasattr(inst, "code"):
104 104 ui.warn(_("abort: %s\n") % inst)
105 105 elif hasattr(inst, "reason"):
106 106 try: # usually it is in the form (errno, strerror)
107 107 reason = inst.reason.args[1]
108 108 except: # it might be anything, for example a string
109 109 reason = inst.reason
110 110 ui.warn(_("abort: error: %s\n") % reason)
111 111 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
112 112 if ui.debugflag:
113 113 ui.warn(_("broken pipe\n"))
114 114 elif getattr(inst, "strerror", None):
115 115 if getattr(inst, "filename", None):
116 116 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
117 117 else:
118 118 ui.warn(_("abort: %s\n") % inst.strerror)
119 119 else:
120 120 raise
121 121 except OSError, inst:
122 122 if getattr(inst, "filename", None):
123 123 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
124 124 else:
125 125 ui.warn(_("abort: %s\n") % inst.strerror)
126 126 except KeyboardInterrupt:
127 127 try:
128 128 ui.warn(_("interrupted!\n"))
129 129 except IOError, inst:
130 130 if inst.errno == errno.EPIPE:
131 131 if ui.debugflag:
132 132 ui.warn(_("\nbroken pipe\n"))
133 133 else:
134 134 raise
135 135 except MemoryError:
136 136 ui.warn(_("abort: out of memory\n"))
137 137 except SystemExit, inst:
138 138 # Commands shouldn't sys.exit directly, but give a return code.
139 139 # Just in case catch this and and pass exit code to caller.
140 140 return inst.code
141 141 except socket.error, inst:
142 142 ui.warn(_("abort: %s\n") % inst.args[-1])
143 143 except:
144 144 ui.warn(_("** unknown exception encountered, details follow\n"))
145 145 ui.warn(_("** report bug details to "
146 146 "http://mercurial.selenic.com/bts/\n"))
147 147 ui.warn(_("** or mercurial@selenic.com\n"))
148 148 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
149 149 % util.version())
150 150 ui.warn(_("** Extensions loaded: %s\n")
151 151 % ", ".join([x[0] for x in extensions.extensions()]))
152 152 raise
153 153
154 154 return -1
155 155
156 156 def _findrepo(p):
157 157 while not os.path.isdir(os.path.join(p, ".hg")):
158 158 oldp, p = p, os.path.dirname(p)
159 159 if p == oldp:
160 160 return None
161 161
162 162 return p
163 163
164 164 def aliasargs(fn):
165 165 if hasattr(fn, 'args'):
166 166 return fn.args
167 167 return []
168 168
169 169 class cmdalias(object):
170 170 def __init__(self, name, definition, cmdtable):
171 171 self.name = name
172 172 self.definition = definition
173 173 self.args = []
174 174 self.opts = []
175 175 self.help = ''
176 176 self.norepo = True
177 177
178 178 try:
179 179 cmdutil.findcmd(self.name, cmdtable, True)
180 180 self.shadows = True
181 181 except error.UnknownCommand:
182 182 self.shadows = False
183 183
184 184 if not self.definition:
185 185 def fn(ui, *args):
186 186 ui.warn(_("no definition for alias '%s'\n") % self.name)
187 187 return 1
188 188 self.fn = fn
189 189
190 190 return
191 191
192 192 args = shlex.split(self.definition)
193 193 cmd = args.pop(0)
194 194 opts = []
195 195 help = ''
196 196
197 197 try:
198 198 self.fn, self.opts, self.help = cmdutil.findcmd(cmd, cmdtable, False)[1]
199 199 self.args = aliasargs(self.fn) + args
200 200 if cmd not in commands.norepo.split(' '):
201 201 self.norepo = False
202 202 except error.UnknownCommand:
203 203 def fn(ui, *args):
204 204 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
205 205 % (self.name, cmd))
206 206 return 1
207 207 self.fn = fn
208 208 except error.AmbiguousCommand:
209 209 def fn(ui, *args):
210 210 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
211 211 % (self.name, cmd))
212 212 return 1
213 213 self.fn = fn
214 214
215 215 def __call__(self, ui, *args, **opts):
216 216 if self.shadows:
217 217 ui.debug(_("alias '%s' shadows command\n") % self.name)
218 218
219 219 return self.fn(ui, *args, **opts)
220 220
221 221 def addaliases(ui, cmdtable):
222 222 # aliases are processed after extensions have been loaded, so they
223 223 # may use extension commands. Aliases can also use other alias definitions,
224 224 # but only if they have been defined prior to the current definition.
225 225 for alias, definition in ui.configitems('alias'):
226 226 aliasdef = cmdalias(alias, definition, cmdtable)
227 227 cmdtable[alias] = (aliasdef, aliasdef.opts, aliasdef.help)
228 228 if aliasdef.norepo:
229 229 commands.norepo += ' %s' % alias
230 230
231 231 def _parse(ui, args):
232 232 options = {}
233 233 cmdoptions = {}
234 234
235 235 try:
236 236 args = fancyopts.fancyopts(args, commands.globalopts, options)
237 237 except fancyopts.getopt.GetoptError, inst:
238 238 raise error.ParseError(None, inst)
239 239
240 240 if args:
241 241 cmd, args = args[0], args[1:]
242 242 aliases, i = cmdutil.findcmd(cmd, commands.table,
243 243 ui.config("ui", "strict"))
244 244 cmd = aliases[0]
245 245 args = aliasargs(i[0]) + args
246 246 defaults = ui.config("defaults", cmd)
247 247 if defaults:
248 248 args = shlex.split(defaults) + args
249 249 c = list(i[1])
250 250 else:
251 251 cmd = None
252 252 c = []
253 253
254 254 # combine global options into local
255 255 for o in commands.globalopts:
256 256 c.append((o[0], o[1], options[o[1]], o[3]))
257 257
258 258 try:
259 259 args = fancyopts.fancyopts(args, c, cmdoptions, True)
260 260 except fancyopts.getopt.GetoptError, inst:
261 261 raise error.ParseError(cmd, inst)
262 262
263 263 # separate global options back out
264 264 for o in commands.globalopts:
265 265 n = o[1]
266 266 options[n] = cmdoptions[n]
267 267 del cmdoptions[n]
268 268
269 269 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
270 270
271 271 def _parseconfig(ui, config):
272 272 """parse the --config options from the command line"""
273 273 for cfg in config:
274 274 try:
275 275 name, value = cfg.split('=', 1)
276 276 section, name = name.split('.', 1)
277 277 if not section or not name:
278 278 raise IndexError
279 279 ui.setconfig(section, name, value)
280 280 except (IndexError, ValueError):
281 281 raise util.Abort(_('malformed --config option: %s') % cfg)
282 282
283 283 def _earlygetopt(aliases, args):
284 284 """Return list of values for an option (or aliases).
285 285
286 286 The values are listed in the order they appear in args.
287 287 The options and values are removed from args.
288 288 """
289 289 try:
290 290 argcount = args.index("--")
291 291 except ValueError:
292 292 argcount = len(args)
293 293 shortopts = [opt for opt in aliases if len(opt) == 2]
294 294 values = []
295 295 pos = 0
296 296 while pos < argcount:
297 297 if args[pos] in aliases:
298 298 if pos + 1 >= argcount:
299 299 # ignore and let getopt report an error if there is no value
300 300 break
301 301 del args[pos]
302 302 values.append(args.pop(pos))
303 303 argcount -= 2
304 304 elif args[pos][:2] in shortopts:
305 305 # short option can have no following space, e.g. hg log -Rfoo
306 306 values.append(args.pop(pos)[2:])
307 307 argcount -= 1
308 308 else:
309 309 pos += 1
310 310 return values
311 311
312 312 def runcommand(lui, repo, cmd, fullargs, ui, options, d):
313 313 # run pre-hook, and abort if it fails
314 314 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
315 315 if ret:
316 316 return ret
317 317 ret = _runcommand(ui, options, cmd, d)
318 318 # run post-hook, passing command result
319 319 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
320 320 result = ret)
321 321 return ret
322 322
323 323 _loaded = set()
324 324 def _dispatch(ui, args):
325 325 # read --config before doing anything else
326 326 # (e.g. to change trust settings for reading .hg/hgrc)
327 327 _parseconfig(ui, _earlygetopt(['--config'], args))
328 328
329 329 # check for cwd
330 330 cwd = _earlygetopt(['--cwd'], args)
331 331 if cwd:
332 332 os.chdir(cwd[-1])
333 333
334 334 # read the local repository .hgrc into a local ui object
335 335 path = _findrepo(os.getcwd()) or ""
336 336 if not path:
337 337 lui = ui
338 if path:
338 else:
339 339 try:
340 340 lui = ui.copy()
341 341 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
342 342 except IOError:
343 343 pass
344 344
345 345 # now we can expand paths, even ones in .hg/hgrc
346 346 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
347 347 if rpath:
348 348 path = lui.expandpath(rpath[-1])
349 349 lui = ui.copy()
350 350 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
351 351
352 352 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
353 353 # reposetup. Programs like TortoiseHg will call _dispatch several
354 354 # times so we keep track of configured extensions in _loaded.
355 355 extensions.loadall(lui)
356 356 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
357 357
358 358 # (uisetup is handled in extensions.loadall)
359 359
360 360 for name, module in exts:
361 361 extsetup = getattr(module, 'extsetup', None)
362 362 if extsetup:
363 363 try:
364 364 extsetup(ui)
365 365 except TypeError:
366 366 if extsetup.func_code.co_argcount != 0:
367 367 raise
368 368 extsetup() # old extsetup with no ui argument
369 369
370 370 for name, module in exts:
371 371 cmdtable = getattr(module, 'cmdtable', {})
372 372 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
373 373 if overrides:
374 374 ui.warn(_("extension '%s' overrides commands: %s\n")
375 375 % (name, " ".join(overrides)))
376 376 commands.table.update(cmdtable)
377 377 _loaded.add(name)
378 378
379 379 # (reposetup is handled in hg.repository)
380 380
381 381 addaliases(lui, commands.table)
382 382
383 383 # check for fallback encoding
384 384 fallback = lui.config('ui', 'fallbackencoding')
385 385 if fallback:
386 386 encoding.fallbackencoding = fallback
387 387
388 388 fullargs = args
389 389 cmd, func, args, options, cmdoptions = _parse(lui, args)
390 390
391 391 if options["config"]:
392 392 raise util.Abort(_("Option --config may not be abbreviated!"))
393 393 if options["cwd"]:
394 394 raise util.Abort(_("Option --cwd may not be abbreviated!"))
395 395 if options["repository"]:
396 396 raise util.Abort(_(
397 397 "Option -R has to be separated from other options (e.g. not -qR) "
398 398 "and --repository may only be abbreviated as --repo!"))
399 399
400 400 if options["encoding"]:
401 401 encoding.encoding = options["encoding"]
402 402 if options["encodingmode"]:
403 403 encoding.encodingmode = options["encodingmode"]
404 404 if options["time"]:
405 405 def get_times():
406 406 t = os.times()
407 407 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
408 408 t = (t[0], t[1], t[2], t[3], time.clock())
409 409 return t
410 410 s = get_times()
411 411 def print_time():
412 412 t = get_times()
413 413 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
414 414 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
415 415 atexit.register(print_time)
416 416
417 417 if options['verbose'] or options['debug'] or options['quiet']:
418 418 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
419 419 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
420 420 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
421 421 if options['traceback']:
422 422 ui.setconfig('ui', 'traceback', 'on')
423 423 if options['noninteractive']:
424 424 ui.setconfig('ui', 'interactive', 'off')
425 425
426 426 if options['help']:
427 427 return commands.help_(ui, cmd, options['version'])
428 428 elif options['version']:
429 429 return commands.version_(ui)
430 430 elif not cmd:
431 431 return commands.help_(ui, 'shortlist')
432 432
433 433 repo = None
434 434 if cmd not in commands.norepo.split():
435 435 try:
436 436 repo = hg.repository(ui, path=path)
437 437 ui = repo.ui
438 438 if not repo.local():
439 439 raise util.Abort(_("repository '%s' is not local") % path)
440 440 ui.setconfig("bundle", "mainreporoot", repo.root)
441 441 except error.RepoError:
442 442 if cmd not in commands.optionalrepo.split():
443 443 if args and not path: # try to infer -R from command args
444 444 repos = map(_findrepo, args)
445 445 guess = repos[0]
446 446 if guess and repos.count(guess) == len(repos):
447 447 return _dispatch(ui, ['--repository', guess] + fullargs)
448 448 if not path:
449 449 raise error.RepoError(_("There is no Mercurial repository"
450 450 " here (.hg not found)"))
451 451 raise
452 452 args.insert(0, repo)
453 453 elif rpath:
454 454 ui.warn("warning: --repository ignored\n")
455 455
456 456 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
457 457 return runcommand(lui, repo, cmd, fullargs, ui, options, d)
458 458
459 459 def _runcommand(ui, options, cmd, cmdfunc):
460 460 def checkargs():
461 461 try:
462 462 return cmdfunc()
463 463 except error.SignatureError:
464 464 raise error.ParseError(cmd, _("invalid arguments"))
465 465
466 466 if options['profile']:
467 467 format = ui.config('profiling', 'format', default='text')
468 468
469 469 if not format in ['text', 'kcachegrind']:
470 470 ui.warn(_("unrecognized profiling format '%s'"
471 471 " - Ignored\n") % format)
472 472 format = 'text'
473 473
474 474 output = ui.config('profiling', 'output')
475 475
476 476 if output:
477 477 path = os.path.expanduser(output)
478 478 path = ui.expandpath(path)
479 479 ostream = open(path, 'wb')
480 480 else:
481 481 ostream = sys.stderr
482 482
483 483 try:
484 484 from mercurial import lsprof
485 485 except ImportError:
486 486 raise util.Abort(_(
487 487 'lsprof not available - install from '
488 488 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
489 489 p = lsprof.Profiler()
490 490 p.enable(subcalls=True)
491 491 try:
492 492 return checkargs()
493 493 finally:
494 494 p.disable()
495 495
496 496 if format == 'kcachegrind':
497 497 import lsprofcalltree
498 498 calltree = lsprofcalltree.KCacheGrind(p)
499 499 calltree.output(ostream)
500 500 else:
501 501 # format == 'text'
502 502 stats = lsprof.Stats(p.getstats())
503 503 stats.sort()
504 504 stats.pprint(top=10, file=ostream, climit=5)
505 505
506 506 if output:
507 507 ostream.close()
508 508 else:
509 509 return checkargs()
@@ -1,43 +1,44 b''
1 1 # repo.py - repository base classes for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2, incorporated herein by reference.
8 8
9 9 from i18n import _
10 10 import error
11 11
12 12 class repository(object):
13 13 def capable(self, name):
14 14 '''tell whether repo supports named capability.
15 15 return False if not supported.
16 16 if boolean capability, return True.
17 17 if string capability, return string.'''
18 18 if name in self.capabilities:
19 19 return True
20 20 name_eq = name + '='
21 21 for cap in self.capabilities:
22 22 if cap.startswith(name_eq):
23 23 return cap[len(name_eq):]
24 24 return False
25 25
26 26 def requirecap(self, name, purpose):
27 27 '''raise an exception if the given capability is not present'''
28 28 if not self.capable(name):
29 29 raise error.CapabilityError(
30 30 _('cannot %s; remote repository does not '
31 31 'support the %r capability') % (purpose, name))
32 32
33 33 def local(self):
34 34 return False
35 35
36 36 def cancopy(self):
37 37 return self.local()
38 38
39 39 def rjoin(self, path):
40 40 url = self.url()
41 41 if url.endswith('/'):
42 42 return url + path
43 return url + '/' + path
43 else:
44 return url + '/' + path
@@ -1,381 +1,381 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 of the
6 6 # GNU General Public License version 2, incorporated herein by reference.
7 7
8 8 from i18n import _
9 9 import errno, getpass, os, socket, sys, tempfile, traceback
10 10 import config, util, error
11 11
12 12 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True,
13 13 '0': False, 'no': False, 'false': False, 'off': False}
14 14
15 15 class ui(object):
16 16 def __init__(self, src=None):
17 17 self._buffers = []
18 18 self.quiet = self.verbose = self.debugflag = self._traceback = False
19 19 self._reportuntrusted = True
20 20 self._ocfg = config.config() # overlay
21 21 self._tcfg = config.config() # trusted
22 22 self._ucfg = config.config() # untrusted
23 23 self._trustusers = set()
24 24 self._trustgroups = set()
25 25
26 26 if src:
27 27 self._tcfg = src._tcfg.copy()
28 28 self._ucfg = src._ucfg.copy()
29 29 self._ocfg = src._ocfg.copy()
30 30 self._trustusers = src._trustusers.copy()
31 31 self._trustgroups = src._trustgroups.copy()
32 32 self.fixconfig()
33 33 else:
34 34 # we always trust global config files
35 35 for f in util.rcpath():
36 36 self.readconfig(f, trust=True)
37 37
38 38 def copy(self):
39 39 return self.__class__(self)
40 40
41 41 def _is_trusted(self, fp, f):
42 42 st = util.fstat(fp)
43 43 if util.isowner(st):
44 44 return True
45 45
46 46 tusers, tgroups = self._trustusers, self._trustgroups
47 47 if '*' in tusers or '*' in tgroups:
48 48 return True
49 49
50 50 user = util.username(st.st_uid)
51 51 group = util.groupname(st.st_gid)
52 52 if user in tusers or group in tgroups or user == util.username():
53 53 return True
54 54
55 55 if self._reportuntrusted:
56 56 self.warn(_('Not trusting file %s from untrusted '
57 57 'user %s, group %s\n') % (f, user, group))
58 58 return False
59 59
60 60 def readconfig(self, filename, root=None, trust=False,
61 61 sections=None, remap=None):
62 62 try:
63 63 fp = open(filename)
64 64 except IOError:
65 65 if not sections: # ignore unless we were looking for something
66 66 return
67 67 raise
68 68
69 69 cfg = config.config()
70 70 trusted = sections or trust or self._is_trusted(fp, filename)
71 71
72 72 try:
73 73 cfg.read(filename, fp, sections=sections, remap=remap)
74 74 except error.ConfigError, inst:
75 75 if trusted:
76 76 raise
77 77 self.warn(_("Ignored: %s\n") % str(inst))
78 78
79 79 if trusted:
80 80 self._tcfg.update(cfg)
81 81 self._tcfg.update(self._ocfg)
82 82 self._ucfg.update(cfg)
83 83 self._ucfg.update(self._ocfg)
84 84
85 85 if root is None:
86 86 root = os.path.expanduser('~')
87 87 self.fixconfig(root=root)
88 88
89 89 def fixconfig(self, root=None):
90 90 # translate paths relative to root (or home) into absolute paths
91 91 root = root or os.getcwd()
92 92 for c in self._tcfg, self._ucfg, self._ocfg:
93 93 for n, p in c.items('paths'):
94 94 if p and "://" not in p and not os.path.isabs(p):
95 95 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
96 96
97 97 # update ui options
98 98 self.debugflag = self.configbool('ui', 'debug')
99 99 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
100 100 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
101 101 if self.verbose and self.quiet:
102 102 self.quiet = self.verbose = False
103 103 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
104 104 self._traceback = self.configbool('ui', 'traceback', False)
105 105
106 106 # update trust information
107 107 self._trustusers.update(self.configlist('trusted', 'users'))
108 108 self._trustgroups.update(self.configlist('trusted', 'groups'))
109 109
110 110 def setconfig(self, section, name, value):
111 111 for cfg in (self._ocfg, self._tcfg, self._ucfg):
112 112 cfg.set(section, name, value)
113 113 self.fixconfig()
114 114
115 115 def _data(self, untrusted):
116 116 return untrusted and self._ucfg or self._tcfg
117 117
118 118 def configsource(self, section, name, untrusted=False):
119 119 return self._data(untrusted).source(section, name) or 'none'
120 120
121 121 def config(self, section, name, default=None, untrusted=False):
122 122 value = self._data(untrusted).get(section, name, default)
123 123 if self.debugflag and not untrusted and self._reportuntrusted:
124 124 uvalue = self._ucfg.get(section, name)
125 125 if uvalue is not None and uvalue != value:
126 126 self.debug(_("ignoring untrusted configuration option "
127 127 "%s.%s = %s\n") % (section, name, uvalue))
128 128 return value
129 129
130 130 def configbool(self, section, name, default=False, untrusted=False):
131 131 v = self.config(section, name, None, untrusted)
132 132 if v is None:
133 133 return default
134 134 if v.lower() not in _booleans:
135 135 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
136 136 % (section, name, v))
137 137 return _booleans[v.lower()]
138 138
139 139 def configlist(self, section, name, default=None, untrusted=False):
140 140 """Return a list of comma/space separated strings"""
141 141 result = self.config(section, name, untrusted=untrusted)
142 142 if result is None:
143 143 result = default or []
144 144 if isinstance(result, basestring):
145 145 result = result.replace(",", " ").split()
146 146 return result
147 147
148 148 def has_section(self, section, untrusted=False):
149 149 '''tell whether section exists in config.'''
150 150 return section in self._data(untrusted)
151 151
152 152 def configitems(self, section, untrusted=False):
153 153 items = self._data(untrusted).items(section)
154 154 if self.debugflag and not untrusted and self._reportuntrusted:
155 155 for k, v in self._ucfg.items(section):
156 156 if self._tcfg.get(section, k) != v:
157 157 self.debug(_("ignoring untrusted configuration option "
158 158 "%s.%s = %s\n") % (section, k, v))
159 159 return items
160 160
161 161 def walkconfig(self, untrusted=False):
162 162 cfg = self._data(untrusted)
163 163 for section in cfg.sections():
164 164 for name, value in self.configitems(section, untrusted):
165 165 yield section, name, str(value).replace('\n', '\\n')
166 166
167 167 def username(self):
168 168 """Return default username to be used in commits.
169 169
170 170 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
171 171 and stop searching if one of these is set.
172 172 If not found and ui.askusername is True, ask the user, else use
173 173 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
174 174 """
175 175 user = os.environ.get("HGUSER")
176 176 if user is None:
177 177 user = self.config("ui", "username")
178 178 if user is None:
179 179 user = os.environ.get("EMAIL")
180 180 if user is None and self.configbool("ui", "askusername"):
181 181 user = self.prompt(_("enter a commit username:"), default=None)
182 182 if user is None:
183 183 try:
184 184 user = '%s@%s' % (util.getuser(), socket.getfqdn())
185 185 self.warn(_("No username found, using '%s' instead\n") % user)
186 186 except KeyError:
187 187 pass
188 188 if not user:
189 189 raise util.Abort(_("Please specify a username."))
190 190 if "\n" in user:
191 191 raise util.Abort(_("username %s contains a newline\n") % repr(user))
192 192 return user
193 193
194 194 def shortuser(self, user):
195 195 """Return a short representation of a user name or email address."""
196 196 if not self.verbose: user = util.shortuser(user)
197 197 return user
198 198
199 199 def _path(self, loc):
200 200 p = self.config('paths', loc)
201 201 if p and '%%' in p:
202 self.warn('(deprecated \'%%\' in path %s=%s from %s)\n' %
202 self.warn("(deprecated '%%' in path %s=%s from %s)\n" %
203 203 (loc, p, self.configsource('paths', loc)))
204 204 p = p.replace('%%', '%')
205 205 return p
206 206
207 207 def expandpath(self, loc, default=None):
208 208 """Return repository location relative to cwd or from [paths]"""
209 209 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
210 210 return loc
211 211
212 212 path = self._path(loc)
213 213 if not path and default is not None:
214 214 path = self._path(default)
215 215 return path or loc
216 216
217 217 def pushbuffer(self):
218 218 self._buffers.append([])
219 219
220 220 def popbuffer(self):
221 221 return "".join(self._buffers.pop())
222 222
223 223 def write(self, *args):
224 224 if self._buffers:
225 225 self._buffers[-1].extend([str(a) for a in args])
226 226 else:
227 227 for a in args:
228 228 sys.stdout.write(str(a))
229 229
230 230 def write_err(self, *args):
231 231 try:
232 232 if not sys.stdout.closed: sys.stdout.flush()
233 233 for a in args:
234 234 sys.stderr.write(str(a))
235 235 # stderr may be buffered under win32 when redirected to files,
236 236 # including stdout.
237 237 if not sys.stderr.closed: sys.stderr.flush()
238 238 except IOError, inst:
239 239 if inst.errno != errno.EPIPE:
240 240 raise
241 241
242 242 def flush(self):
243 243 try: sys.stdout.flush()
244 244 except: pass
245 245 try: sys.stderr.flush()
246 246 except: pass
247 247
248 248 def interactive(self):
249 249 i = self.configbool("ui", "interactive", None)
250 250 if i is None:
251 251 return sys.stdin.isatty()
252 252 return i
253 253
254 254 def _readline(self, prompt=''):
255 255 if sys.stdin.isatty():
256 256 try:
257 257 # magically add command line editing support, where
258 258 # available
259 259 import readline
260 260 # force demandimport to really load the module
261 261 readline.read_history_file
262 262 # windows sometimes raises something other than ImportError
263 263 except Exception:
264 264 pass
265 265 line = raw_input(prompt)
266 266 # When stdin is in binary mode on Windows, it can cause
267 267 # raw_input() to emit an extra trailing carriage return
268 268 if os.linesep == '\r\n' and line and line[-1] == '\r':
269 269 line = line[:-1]
270 270 return line
271 271
272 272 def prompt(self, msg, default="y"):
273 273 """Prompt user with msg, read response.
274 274 If ui is not interactive, the default is returned.
275 275 """
276 276 if not self.interactive():
277 277 self.write(msg, ' ', default, "\n")
278 278 return default
279 279 try:
280 280 r = self._readline(msg + ' ')
281 281 if not r:
282 282 return default
283 283 return r
284 284 except EOFError:
285 285 raise util.Abort(_('response expected'))
286 286
287 287 def promptchoice(self, msg, choices, default=0):
288 288 """Prompt user with msg, read response, and ensure it matches
289 289 one of the provided choices. The index of the choice is returned.
290 290 choices is a sequence of acceptable responses with the format:
291 291 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
292 292 If ui is not interactive, the default is returned.
293 293 """
294 294 resps = [s[s.index('&')+1].lower() for s in choices]
295 295 while True:
296 296 r = self.prompt(msg, resps[default])
297 297 if r.lower() in resps:
298 298 return resps.index(r.lower())
299 299 self.write(_("unrecognized response\n"))
300 300
301 301
302 302 def getpass(self, prompt=None, default=None):
303 303 if not self.interactive(): return default
304 304 try:
305 305 return getpass.getpass(prompt or _('password: '))
306 306 except EOFError:
307 307 raise util.Abort(_('response expected'))
308 308 def status(self, *msg):
309 309 if not self.quiet: self.write(*msg)
310 310 def warn(self, *msg):
311 311 self.write_err(*msg)
312 312 def note(self, *msg):
313 313 if self.verbose: self.write(*msg)
314 314 def debug(self, *msg):
315 315 if self.debugflag: self.write(*msg)
316 316 def edit(self, text, user):
317 317 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
318 318 text=True)
319 319 try:
320 320 f = os.fdopen(fd, "w")
321 321 f.write(text)
322 322 f.close()
323 323
324 324 editor = self.geteditor()
325 325
326 326 util.system("%s \"%s\"" % (editor, name),
327 327 environ={'HGUSER': user},
328 328 onerr=util.Abort, errprefix=_("edit failed"))
329 329
330 330 f = open(name)
331 331 t = f.read()
332 332 f.close()
333 333 finally:
334 334 os.unlink(name)
335 335
336 336 return t
337 337
338 338 def traceback(self):
339 339 '''print exception traceback if traceback printing enabled.
340 340 only to call in exception handler. returns true if traceback
341 341 printed.'''
342 342 if self._traceback:
343 343 traceback.print_exc()
344 344 return self._traceback
345 345
346 346 def geteditor(self):
347 347 '''return editor to use'''
348 348 return (os.environ.get("HGEDITOR") or
349 349 self.config("ui", "editor") or
350 350 os.environ.get("VISUAL") or
351 351 os.environ.get("EDITOR", "vi"))
352 352
353 353 def progress(self, topic, pos, item="", unit="", total=None):
354 354 '''show a progress message
355 355
356 356 With stock hg, this is simply a debug message that is hidden
357 357 by default, but with extensions or GUI tools it may be
358 358 visible. 'topic' is the current operation, 'item' is a
359 359 non-numeric marker of the current position (ie the currently
360 360 in-process file), 'pos' is the current numeric position (ie
361 361 revision, bytes, etc.), unit is a corresponding unit label,
362 362 and total is the highest expected pos.
363 363
364 364 Multiple nested topics may be active at a time. All topics
365 365 should be marked closed by setting pos to None at termination.
366 366 '''
367 367
368 368 if pos == None or not self.debugflag:
369 369 return
370 370
371 371 if unit:
372 372 unit = ' ' + unit
373 373 if item:
374 374 item = ' ' + item
375 375
376 376 if total:
377 377 pct = 100.0 * pos / total
378 378 ui.debug('%s:%s %s/%s%s (%4.2g%%)\n'
379 379 % (topic, item, pos, total, unit, pct))
380 380 else:
381 381 ui.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
General Comments 0
You need to be logged in to leave comments. Login now