##// END OF EJS Templates
config: give a useful hint of source for the most common command line settings...
Mads Kiilerich -
r20788:f144928d default
parent child Browse files
Show More
@@ -1,897 +1,897 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 or any later version.
7 7
8 8 from i18n import _
9 9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 10 import util, commands, hg, fancyopts, extensions, hook, error
11 11 import cmdutil, encoding
12 12 import ui as uimod
13 13
14 14 class request(object):
15 15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 16 ferr=None):
17 17 self.args = args
18 18 self.ui = ui
19 19 self.repo = repo
20 20
21 21 # input/output/error streams
22 22 self.fin = fin
23 23 self.fout = fout
24 24 self.ferr = ferr
25 25
26 26 def run():
27 27 "run the command in sys.argv"
28 28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29 29
30 30 def dispatch(req):
31 31 "run the command specified in req.args"
32 32 if req.ferr:
33 33 ferr = req.ferr
34 34 elif req.ui:
35 35 ferr = req.ui.ferr
36 36 else:
37 37 ferr = sys.stderr
38 38
39 39 try:
40 40 if not req.ui:
41 41 req.ui = uimod.ui()
42 42 if '--traceback' in req.args:
43 req.ui.setconfig('ui', 'traceback', 'on')
43 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
44 44
45 45 # set ui streams from the request
46 46 if req.fin:
47 47 req.ui.fin = req.fin
48 48 if req.fout:
49 49 req.ui.fout = req.fout
50 50 if req.ferr:
51 51 req.ui.ferr = req.ferr
52 52 except util.Abort, inst:
53 53 ferr.write(_("abort: %s\n") % inst)
54 54 if inst.hint:
55 55 ferr.write(_("(%s)\n") % inst.hint)
56 56 return -1
57 57 except error.ParseError, inst:
58 58 if len(inst.args) > 1:
59 59 ferr.write(_("hg: parse error at %s: %s\n") %
60 60 (inst.args[1], inst.args[0]))
61 61 else:
62 62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
63 63 return -1
64 64
65 65 msg = ' '.join(' ' in a and repr(a) or a for a in req.args)
66 66 starttime = time.time()
67 67 ret = None
68 68 try:
69 69 ret = _runcatch(req)
70 70 return ret
71 71 finally:
72 72 duration = time.time() - starttime
73 73 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
74 74 msg, ret or 0, duration)
75 75
76 76 def _runcatch(req):
77 77 def catchterm(*args):
78 78 raise error.SignalInterrupt
79 79
80 80 ui = req.ui
81 81 try:
82 82 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
83 83 num = getattr(signal, name, None)
84 84 if num:
85 85 signal.signal(num, catchterm)
86 86 except ValueError:
87 87 pass # happens if called in a thread
88 88
89 89 try:
90 90 try:
91 91 debugger = 'pdb'
92 92 debugtrace = {
93 93 'pdb' : pdb.set_trace
94 94 }
95 95 debugmortem = {
96 96 'pdb' : pdb.post_mortem
97 97 }
98 98
99 99 # read --config before doing anything else
100 100 # (e.g. to change trust settings for reading .hg/hgrc)
101 101 cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
102 102
103 103 if req.repo:
104 104 # copy configs that were passed on the cmdline (--config) to
105 105 # the repo ui
106 106 for cfg in cfgs:
107 req.repo.ui.setconfig(*cfg)
107 req.repo.ui.setconfig(*cfg, source='--config')
108 108
109 109 # if we are in HGPLAIN mode, then disable custom debugging
110 110 debugger = ui.config("ui", "debugger")
111 111 if not debugger or ui.plain():
112 112 debugger = 'pdb'
113 113
114 114 try:
115 115 debugmod = __import__(debugger)
116 116 except ImportError:
117 117 debugmod = pdb
118 118
119 119 debugtrace[debugger] = debugmod.set_trace
120 120 debugmortem[debugger] = debugmod.post_mortem
121 121
122 122 # enter the debugger before command execution
123 123 if '--debugger' in req.args:
124 124 ui.warn(_("entering debugger - "
125 125 "type c to continue starting hg or h for help\n"))
126 126
127 127 if (debugger != 'pdb' and
128 128 debugtrace[debugger] == debugtrace['pdb']):
129 129 ui.warn(_("%s debugger specified "
130 130 "but its module was not found\n") % debugger)
131 131
132 132 debugtrace[debugger]()
133 133 try:
134 134 return _dispatch(req)
135 135 finally:
136 136 ui.flush()
137 137 except: # re-raises
138 138 # enter the debugger when we hit an exception
139 139 if '--debugger' in req.args:
140 140 traceback.print_exc()
141 141 debugmortem[debugger](sys.exc_info()[2])
142 142 ui.traceback()
143 143 raise
144 144
145 145 # Global exception handling, alphabetically
146 146 # Mercurial-specific first, followed by built-in and library exceptions
147 147 except error.AmbiguousCommand, inst:
148 148 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
149 149 (inst.args[0], " ".join(inst.args[1])))
150 150 except error.ParseError, inst:
151 151 if len(inst.args) > 1:
152 152 ui.warn(_("hg: parse error at %s: %s\n") %
153 153 (inst.args[1], inst.args[0]))
154 154 else:
155 155 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
156 156 return -1
157 157 except error.LockHeld, inst:
158 158 if inst.errno == errno.ETIMEDOUT:
159 159 reason = _('timed out waiting for lock held by %s') % inst.locker
160 160 else:
161 161 reason = _('lock held by %s') % inst.locker
162 162 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
163 163 except error.LockUnavailable, inst:
164 164 ui.warn(_("abort: could not lock %s: %s\n") %
165 165 (inst.desc or inst.filename, inst.strerror))
166 166 except error.CommandError, inst:
167 167 if inst.args[0]:
168 168 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
169 169 commands.help_(ui, inst.args[0], full=False, command=True)
170 170 else:
171 171 ui.warn(_("hg: %s\n") % inst.args[1])
172 172 commands.help_(ui, 'shortlist')
173 173 except error.OutOfBandError, inst:
174 174 ui.warn(_("abort: remote error:\n"))
175 175 ui.warn(''.join(inst.args))
176 176 except error.RepoError, inst:
177 177 ui.warn(_("abort: %s!\n") % inst)
178 178 if inst.hint:
179 179 ui.warn(_("(%s)\n") % inst.hint)
180 180 except error.ResponseError, inst:
181 181 ui.warn(_("abort: %s") % inst.args[0])
182 182 if not isinstance(inst.args[1], basestring):
183 183 ui.warn(" %r\n" % (inst.args[1],))
184 184 elif not inst.args[1]:
185 185 ui.warn(_(" empty string\n"))
186 186 else:
187 187 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
188 188 except error.RevlogError, inst:
189 189 ui.warn(_("abort: %s!\n") % inst)
190 190 except error.SignalInterrupt:
191 191 ui.warn(_("killed!\n"))
192 192 except error.UnknownCommand, inst:
193 193 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
194 194 try:
195 195 # check if the command is in a disabled extension
196 196 # (but don't check for extensions themselves)
197 197 commands.help_(ui, inst.args[0], unknowncmd=True)
198 198 except error.UnknownCommand:
199 199 commands.help_(ui, 'shortlist')
200 200 except error.InterventionRequired, inst:
201 201 ui.warn("%s\n" % inst)
202 202 return 1
203 203 except util.Abort, inst:
204 204 ui.warn(_("abort: %s\n") % inst)
205 205 if inst.hint:
206 206 ui.warn(_("(%s)\n") % inst.hint)
207 207 except ImportError, inst:
208 208 ui.warn(_("abort: %s!\n") % inst)
209 209 m = str(inst).split()[-1]
210 210 if m in "mpatch bdiff".split():
211 211 ui.warn(_("(did you forget to compile extensions?)\n"))
212 212 elif m in "zlib".split():
213 213 ui.warn(_("(is your Python install correct?)\n"))
214 214 except IOError, inst:
215 215 if util.safehasattr(inst, "code"):
216 216 ui.warn(_("abort: %s\n") % inst)
217 217 elif util.safehasattr(inst, "reason"):
218 218 try: # usually it is in the form (errno, strerror)
219 219 reason = inst.reason.args[1]
220 220 except (AttributeError, IndexError):
221 221 # it might be anything, for example a string
222 222 reason = inst.reason
223 223 ui.warn(_("abort: error: %s\n") % reason)
224 224 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
225 225 if ui.debugflag:
226 226 ui.warn(_("broken pipe\n"))
227 227 elif getattr(inst, "strerror", None):
228 228 if getattr(inst, "filename", None):
229 229 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
230 230 else:
231 231 ui.warn(_("abort: %s\n") % inst.strerror)
232 232 else:
233 233 raise
234 234 except OSError, inst:
235 235 if getattr(inst, "filename", None) is not None:
236 236 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
237 237 else:
238 238 ui.warn(_("abort: %s\n") % inst.strerror)
239 239 except KeyboardInterrupt:
240 240 try:
241 241 ui.warn(_("interrupted!\n"))
242 242 except IOError, inst:
243 243 if inst.errno == errno.EPIPE:
244 244 if ui.debugflag:
245 245 ui.warn(_("\nbroken pipe\n"))
246 246 else:
247 247 raise
248 248 except MemoryError:
249 249 ui.warn(_("abort: out of memory\n"))
250 250 except SystemExit, inst:
251 251 # Commands shouldn't sys.exit directly, but give a return code.
252 252 # Just in case catch this and and pass exit code to caller.
253 253 return inst.code
254 254 except socket.error, inst:
255 255 ui.warn(_("abort: %s\n") % inst.args[-1])
256 256 except: # re-raises
257 257 myver = util.version()
258 258 # For compatibility checking, we discard the portion of the hg
259 259 # version after the + on the assumption that if a "normal
260 260 # user" is running a build with a + in it the packager
261 261 # probably built from fairly close to a tag and anyone with a
262 262 # 'make local' copy of hg (where the version number can be out
263 263 # of date) will be clueful enough to notice the implausible
264 264 # version number and try updating.
265 265 compare = myver.split('+')[0]
266 266 ct = tuplever(compare)
267 267 worst = None, ct, ''
268 268 for name, mod in extensions.extensions():
269 269 testedwith = getattr(mod, 'testedwith', '')
270 270 report = getattr(mod, 'buglink', _('the extension author.'))
271 271 if not testedwith.strip():
272 272 # We found an untested extension. It's likely the culprit.
273 273 worst = name, 'unknown', report
274 274 break
275 275 if compare not in testedwith.split() and testedwith != 'internal':
276 276 tested = [tuplever(v) for v in testedwith.split()]
277 277 lower = [t for t in tested if t < ct]
278 278 nearest = max(lower or tested)
279 279 if worst[0] is None or nearest < worst[1]:
280 280 worst = name, nearest, report
281 281 if worst[0] is not None:
282 282 name, testedwith, report = worst
283 283 if not isinstance(testedwith, str):
284 284 testedwith = '.'.join([str(c) for c in testedwith])
285 285 warning = (_('** Unknown exception encountered with '
286 286 'possibly-broken third-party extension %s\n'
287 287 '** which supports versions %s of Mercurial.\n'
288 288 '** Please disable %s and try your action again.\n'
289 289 '** If that fixes the bug please report it to %s\n')
290 290 % (name, testedwith, name, report))
291 291 else:
292 292 warning = (_("** unknown exception encountered, "
293 293 "please report by visiting\n") +
294 294 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
295 295 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
296 296 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
297 297 (_("** Extensions loaded: %s\n") %
298 298 ", ".join([x[0] for x in extensions.extensions()])))
299 299 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
300 300 ui.warn(warning)
301 301 raise
302 302
303 303 return -1
304 304
305 305 def tuplever(v):
306 306 try:
307 307 return tuple([int(i) for i in v.split('.')])
308 308 except ValueError:
309 309 return tuple()
310 310
311 311 def aliasargs(fn, givenargs):
312 312 args = getattr(fn, 'args', [])
313 313 if args:
314 314 cmd = ' '.join(map(util.shellquote, args))
315 315
316 316 nums = []
317 317 def replacer(m):
318 318 num = int(m.group(1)) - 1
319 319 nums.append(num)
320 320 if num < len(givenargs):
321 321 return givenargs[num]
322 322 raise util.Abort(_('too few arguments for command alias'))
323 323 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
324 324 givenargs = [x for i, x in enumerate(givenargs)
325 325 if i not in nums]
326 326 args = shlex.split(cmd)
327 327 return args + givenargs
328 328
329 329 class cmdalias(object):
330 330 def __init__(self, name, definition, cmdtable):
331 331 self.name = self.cmd = name
332 332 self.cmdname = ''
333 333 self.definition = definition
334 334 self.args = []
335 335 self.opts = []
336 336 self.help = ''
337 337 self.norepo = True
338 338 self.optionalrepo = False
339 339 self.badalias = False
340 340
341 341 try:
342 342 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
343 343 for alias, e in cmdtable.iteritems():
344 344 if e is entry:
345 345 self.cmd = alias
346 346 break
347 347 self.shadows = True
348 348 except error.UnknownCommand:
349 349 self.shadows = False
350 350
351 351 if not self.definition:
352 352 def fn(ui, *args):
353 353 ui.warn(_("no definition for alias '%s'\n") % self.name)
354 354 return 1
355 355 self.fn = fn
356 356 self.badalias = True
357 357 return
358 358
359 359 if self.definition.startswith('!'):
360 360 self.shell = True
361 361 def fn(ui, *args):
362 362 env = {'HG_ARGS': ' '.join((self.name,) + args)}
363 363 def _checkvar(m):
364 364 if m.groups()[0] == '$':
365 365 return m.group()
366 366 elif int(m.groups()[0]) <= len(args):
367 367 return m.group()
368 368 else:
369 369 ui.debug("No argument found for substitution "
370 370 "of %i variable in alias '%s' definition."
371 371 % (int(m.groups()[0]), self.name))
372 372 return ''
373 373 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
374 374 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
375 375 replace['0'] = self.name
376 376 replace['@'] = ' '.join(args)
377 377 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
378 378 return util.system(cmd, environ=env, out=ui.fout)
379 379 self.fn = fn
380 380 return
381 381
382 382 args = shlex.split(self.definition)
383 383 self.cmdname = cmd = args.pop(0)
384 384 args = map(util.expandpath, args)
385 385
386 386 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
387 387 if _earlygetopt([invalidarg], args):
388 388 def fn(ui, *args):
389 389 ui.warn(_("error in definition for alias '%s': %s may only "
390 390 "be given on the command line\n")
391 391 % (self.name, invalidarg))
392 392 return 1
393 393
394 394 self.fn = fn
395 395 self.badalias = True
396 396 return
397 397
398 398 try:
399 399 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
400 400 if len(tableentry) > 2:
401 401 self.fn, self.opts, self.help = tableentry
402 402 else:
403 403 self.fn, self.opts = tableentry
404 404
405 405 self.args = aliasargs(self.fn, args)
406 406 if cmd not in commands.norepo.split(' '):
407 407 self.norepo = False
408 408 if cmd in commands.optionalrepo.split(' '):
409 409 self.optionalrepo = True
410 410 if self.help.startswith("hg " + cmd):
411 411 # drop prefix in old-style help lines so hg shows the alias
412 412 self.help = self.help[4 + len(cmd):]
413 413 self.__doc__ = self.fn.__doc__
414 414
415 415 except error.UnknownCommand:
416 416 def fn(ui, *args):
417 417 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
418 418 % (self.name, cmd))
419 419 try:
420 420 # check if the command is in a disabled extension
421 421 commands.help_(ui, cmd, unknowncmd=True)
422 422 except error.UnknownCommand:
423 423 pass
424 424 return 1
425 425 self.fn = fn
426 426 self.badalias = True
427 427 except error.AmbiguousCommand:
428 428 def fn(ui, *args):
429 429 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
430 430 % (self.name, cmd))
431 431 return 1
432 432 self.fn = fn
433 433 self.badalias = True
434 434
435 435 def __call__(self, ui, *args, **opts):
436 436 if self.shadows:
437 437 ui.debug("alias '%s' shadows command '%s'\n" %
438 438 (self.name, self.cmdname))
439 439
440 440 if util.safehasattr(self, 'shell'):
441 441 return self.fn(ui, *args, **opts)
442 442 else:
443 443 try:
444 444 util.checksignature(self.fn)(ui, *args, **opts)
445 445 except error.SignatureError:
446 446 args = ' '.join([self.cmdname] + self.args)
447 447 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
448 448 raise
449 449
450 450 def addaliases(ui, cmdtable):
451 451 # aliases are processed after extensions have been loaded, so they
452 452 # may use extension commands. Aliases can also use other alias definitions,
453 453 # but only if they have been defined prior to the current definition.
454 454 for alias, definition in ui.configitems('alias'):
455 455 aliasdef = cmdalias(alias, definition, cmdtable)
456 456
457 457 try:
458 458 olddef = cmdtable[aliasdef.cmd][0]
459 459 if olddef.definition == aliasdef.definition:
460 460 continue
461 461 except (KeyError, AttributeError):
462 462 # definition might not exist or it might not be a cmdalias
463 463 pass
464 464
465 465 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
466 466 if aliasdef.norepo:
467 467 commands.norepo += ' %s' % alias
468 468 if aliasdef.optionalrepo:
469 469 commands.optionalrepo += ' %s' % alias
470 470
471 471 def _parse(ui, args):
472 472 options = {}
473 473 cmdoptions = {}
474 474
475 475 try:
476 476 args = fancyopts.fancyopts(args, commands.globalopts, options)
477 477 except fancyopts.getopt.GetoptError, inst:
478 478 raise error.CommandError(None, inst)
479 479
480 480 if args:
481 481 cmd, args = args[0], args[1:]
482 482 aliases, entry = cmdutil.findcmd(cmd, commands.table,
483 483 ui.configbool("ui", "strict"))
484 484 cmd = aliases[0]
485 485 args = aliasargs(entry[0], args)
486 486 defaults = ui.config("defaults", cmd)
487 487 if defaults:
488 488 args = map(util.expandpath, shlex.split(defaults)) + args
489 489 c = list(entry[1])
490 490 else:
491 491 cmd = None
492 492 c = []
493 493
494 494 # combine global options into local
495 495 for o in commands.globalopts:
496 496 c.append((o[0], o[1], options[o[1]], o[3]))
497 497
498 498 try:
499 499 args = fancyopts.fancyopts(args, c, cmdoptions, True)
500 500 except fancyopts.getopt.GetoptError, inst:
501 501 raise error.CommandError(cmd, inst)
502 502
503 503 # separate global options back out
504 504 for o in commands.globalopts:
505 505 n = o[1]
506 506 options[n] = cmdoptions[n]
507 507 del cmdoptions[n]
508 508
509 509 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
510 510
511 511 def _parseconfig(ui, config):
512 512 """parse the --config options from the command line"""
513 513 configs = []
514 514
515 515 for cfg in config:
516 516 try:
517 517 name, value = cfg.split('=', 1)
518 518 section, name = name.split('.', 1)
519 519 if not section or not name:
520 520 raise IndexError
521 ui.setconfig(section, name, value)
521 ui.setconfig(section, name, value, '--config')
522 522 configs.append((section, name, value))
523 523 except (IndexError, ValueError):
524 524 raise util.Abort(_('malformed --config option: %r '
525 525 '(use --config section.name=value)') % cfg)
526 526
527 527 return configs
528 528
529 529 def _earlygetopt(aliases, args):
530 530 """Return list of values for an option (or aliases).
531 531
532 532 The values are listed in the order they appear in args.
533 533 The options and values are removed from args.
534 534
535 535 >>> args = ['x', '--cwd', 'foo', 'y']
536 536 >>> _earlygetopt(['--cwd'], args), args
537 537 (['foo'], ['x', 'y'])
538 538
539 539 >>> args = ['x', '--cwd=bar', 'y']
540 540 >>> _earlygetopt(['--cwd'], args), args
541 541 (['bar'], ['x', 'y'])
542 542
543 543 >>> args = ['x', '-R', 'foo', 'y']
544 544 >>> _earlygetopt(['-R'], args), args
545 545 (['foo'], ['x', 'y'])
546 546
547 547 >>> args = ['x', '-Rbar', 'y']
548 548 >>> _earlygetopt(['-R'], args), args
549 549 (['bar'], ['x', 'y'])
550 550 """
551 551 try:
552 552 argcount = args.index("--")
553 553 except ValueError:
554 554 argcount = len(args)
555 555 shortopts = [opt for opt in aliases if len(opt) == 2]
556 556 values = []
557 557 pos = 0
558 558 while pos < argcount:
559 559 fullarg = arg = args[pos]
560 560 equals = arg.find('=')
561 561 if equals > -1:
562 562 arg = arg[:equals]
563 563 if arg in aliases:
564 564 del args[pos]
565 565 if equals > -1:
566 566 values.append(fullarg[equals + 1:])
567 567 argcount -= 1
568 568 else:
569 569 if pos + 1 >= argcount:
570 570 # ignore and let getopt report an error if there is no value
571 571 break
572 572 values.append(args.pop(pos))
573 573 argcount -= 2
574 574 elif arg[:2] in shortopts:
575 575 # short option can have no following space, e.g. hg log -Rfoo
576 576 values.append(args.pop(pos)[2:])
577 577 argcount -= 1
578 578 else:
579 579 pos += 1
580 580 return values
581 581
582 582 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
583 583 # run pre-hook, and abort if it fails
584 584 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
585 585 pats=cmdpats, opts=cmdoptions)
586 586 ret = _runcommand(ui, options, cmd, d)
587 587 # run post-hook, passing command result
588 588 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
589 589 result=ret, pats=cmdpats, opts=cmdoptions)
590 590 return ret
591 591
592 592 def _getlocal(ui, rpath):
593 593 """Return (path, local ui object) for the given target path.
594 594
595 595 Takes paths in [cwd]/.hg/hgrc into account."
596 596 """
597 597 try:
598 598 wd = os.getcwd()
599 599 except OSError, e:
600 600 raise util.Abort(_("error getting current working directory: %s") %
601 601 e.strerror)
602 602 path = cmdutil.findrepo(wd) or ""
603 603 if not path:
604 604 lui = ui
605 605 else:
606 606 lui = ui.copy()
607 607 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
608 608
609 609 if rpath and rpath[-1]:
610 610 path = lui.expandpath(rpath[-1])
611 611 lui = ui.copy()
612 612 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
613 613
614 614 return path, lui
615 615
616 616 def _checkshellalias(lui, ui, args):
617 617 options = {}
618 618
619 619 try:
620 620 args = fancyopts.fancyopts(args, commands.globalopts, options)
621 621 except fancyopts.getopt.GetoptError:
622 622 return
623 623
624 624 if not args:
625 625 return
626 626
627 627 norepo = commands.norepo
628 628 optionalrepo = commands.optionalrepo
629 629 def restorecommands():
630 630 commands.norepo = norepo
631 631 commands.optionalrepo = optionalrepo
632 632
633 633 cmdtable = commands.table.copy()
634 634 addaliases(lui, cmdtable)
635 635
636 636 cmd = args[0]
637 637 try:
638 638 aliases, entry = cmdutil.findcmd(cmd, cmdtable)
639 639 except (error.AmbiguousCommand, error.UnknownCommand):
640 640 restorecommands()
641 641 return
642 642
643 643 cmd = aliases[0]
644 644 fn = entry[0]
645 645
646 646 if cmd and util.safehasattr(fn, 'shell'):
647 647 d = lambda: fn(ui, *args[1:])
648 648 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
649 649 [], {})
650 650
651 651 restorecommands()
652 652
653 653 _loaded = set()
654 654 def _dispatch(req):
655 655 args = req.args
656 656 ui = req.ui
657 657
658 658 # check for cwd
659 659 cwd = _earlygetopt(['--cwd'], args)
660 660 if cwd:
661 661 os.chdir(cwd[-1])
662 662
663 663 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
664 664 path, lui = _getlocal(ui, rpath)
665 665
666 666 # Now that we're operating in the right directory/repository with
667 667 # the right config settings, check for shell aliases
668 668 shellaliasfn = _checkshellalias(lui, ui, args)
669 669 if shellaliasfn:
670 670 return shellaliasfn()
671 671
672 672 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
673 673 # reposetup. Programs like TortoiseHg will call _dispatch several
674 674 # times so we keep track of configured extensions in _loaded.
675 675 extensions.loadall(lui)
676 676 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
677 677 # Propagate any changes to lui.__class__ by extensions
678 678 ui.__class__ = lui.__class__
679 679
680 680 # (uisetup and extsetup are handled in extensions.loadall)
681 681
682 682 for name, module in exts:
683 683 cmdtable = getattr(module, 'cmdtable', {})
684 684 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
685 685 if overrides:
686 686 ui.warn(_("extension '%s' overrides commands: %s\n")
687 687 % (name, " ".join(overrides)))
688 688 commands.table.update(cmdtable)
689 689 _loaded.add(name)
690 690
691 691 # (reposetup is handled in hg.repository)
692 692
693 693 addaliases(lui, commands.table)
694 694
695 695 # check for fallback encoding
696 696 fallback = lui.config('ui', 'fallbackencoding')
697 697 if fallback:
698 698 encoding.fallbackencoding = fallback
699 699
700 700 fullargs = args
701 701 cmd, func, args, options, cmdoptions = _parse(lui, args)
702 702
703 703 if options["config"]:
704 704 raise util.Abort(_("option --config may not be abbreviated!"))
705 705 if options["cwd"]:
706 706 raise util.Abort(_("option --cwd may not be abbreviated!"))
707 707 if options["repository"]:
708 708 raise util.Abort(_(
709 709 "option -R has to be separated from other options (e.g. not -qR) "
710 710 "and --repository may only be abbreviated as --repo!"))
711 711
712 712 if options["encoding"]:
713 713 encoding.encoding = options["encoding"]
714 714 if options["encodingmode"]:
715 715 encoding.encodingmode = options["encodingmode"]
716 716 if options["time"]:
717 717 def get_times():
718 718 t = os.times()
719 719 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
720 720 t = (t[0], t[1], t[2], t[3], time.clock())
721 721 return t
722 722 s = get_times()
723 723 def print_time():
724 724 t = get_times()
725 725 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
726 726 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
727 727 atexit.register(print_time)
728 728
729 729 uis = set([ui, lui])
730 730
731 731 if req.repo:
732 732 uis.add(req.repo.ui)
733 733
734 734 if options['verbose'] or options['debug'] or options['quiet']:
735 735 for opt in ('verbose', 'debug', 'quiet'):
736 736 val = str(bool(options[opt]))
737 737 for ui_ in uis:
738 ui_.setconfig('ui', opt, val)
738 ui_.setconfig('ui', opt, val, '--' + opt)
739 739
740 740 if options['traceback']:
741 741 for ui_ in uis:
742 ui_.setconfig('ui', 'traceback', 'on')
742 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
743 743
744 744 if options['noninteractive']:
745 745 for ui_ in uis:
746 ui_.setconfig('ui', 'interactive', 'off')
746 ui_.setconfig('ui', 'interactive', 'off', '-y')
747 747
748 748 if cmdoptions.get('insecure', False):
749 749 for ui_ in uis:
750 ui_.setconfig('web', 'cacerts', '')
750 ui_.setconfig('web', 'cacerts', '', '--insecure')
751 751
752 752 if options['version']:
753 753 return commands.version_(ui)
754 754 if options['help']:
755 755 return commands.help_(ui, cmd)
756 756 elif not cmd:
757 757 return commands.help_(ui, 'shortlist')
758 758
759 759 repo = None
760 760 cmdpats = args[:]
761 761 if cmd not in commands.norepo.split():
762 762 # use the repo from the request only if we don't have -R
763 763 if not rpath and not cwd:
764 764 repo = req.repo
765 765
766 766 if repo:
767 767 # set the descriptors of the repo ui to those of ui
768 768 repo.ui.fin = ui.fin
769 769 repo.ui.fout = ui.fout
770 770 repo.ui.ferr = ui.ferr
771 771 else:
772 772 try:
773 773 repo = hg.repository(ui, path=path)
774 774 if not repo.local():
775 775 raise util.Abort(_("repository '%s' is not local") % path)
776 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
776 repo.ui.setconfig("bundle", "mainreporoot", repo.root, 'repo')
777 777 except error.RequirementError:
778 778 raise
779 779 except error.RepoError:
780 780 if cmd not in commands.optionalrepo.split():
781 781 if (cmd in commands.inferrepo.split() and
782 782 args and not path): # try to infer -R from command args
783 783 repos = map(cmdutil.findrepo, args)
784 784 guess = repos[0]
785 785 if guess and repos.count(guess) == len(repos):
786 786 req.args = ['--repository', guess] + fullargs
787 787 return _dispatch(req)
788 788 if not path:
789 789 raise error.RepoError(_("no repository found in '%s'"
790 790 " (.hg not found)")
791 791 % os.getcwd())
792 792 raise
793 793 if repo:
794 794 ui = repo.ui
795 795 if options['hidden']:
796 796 repo = repo.unfiltered()
797 797 args.insert(0, repo)
798 798 elif rpath:
799 799 ui.warn(_("warning: --repository ignored\n"))
800 800
801 801 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
802 802 ui.log("command", '%s\n', msg)
803 803 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
804 804 try:
805 805 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
806 806 cmdpats, cmdoptions)
807 807 finally:
808 808 if repo and repo != req.repo:
809 809 repo.close()
810 810
811 811 def lsprofile(ui, func, fp):
812 812 format = ui.config('profiling', 'format', default='text')
813 813 field = ui.config('profiling', 'sort', default='inlinetime')
814 814 limit = ui.configint('profiling', 'limit', default=30)
815 815 climit = ui.configint('profiling', 'nested', default=5)
816 816
817 817 if format not in ['text', 'kcachegrind']:
818 818 ui.warn(_("unrecognized profiling format '%s'"
819 819 " - Ignored\n") % format)
820 820 format = 'text'
821 821
822 822 try:
823 823 from mercurial import lsprof
824 824 except ImportError:
825 825 raise util.Abort(_(
826 826 'lsprof not available - install from '
827 827 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
828 828 p = lsprof.Profiler()
829 829 p.enable(subcalls=True)
830 830 try:
831 831 return func()
832 832 finally:
833 833 p.disable()
834 834
835 835 if format == 'kcachegrind':
836 836 import lsprofcalltree
837 837 calltree = lsprofcalltree.KCacheGrind(p)
838 838 calltree.output(fp)
839 839 else:
840 840 # format == 'text'
841 841 stats = lsprof.Stats(p.getstats())
842 842 stats.sort(field)
843 843 stats.pprint(limit=limit, file=fp, climit=climit)
844 844
845 845 def statprofile(ui, func, fp):
846 846 try:
847 847 import statprof
848 848 except ImportError:
849 849 raise util.Abort(_(
850 850 'statprof not available - install using "easy_install statprof"'))
851 851
852 852 freq = ui.configint('profiling', 'freq', default=1000)
853 853 if freq > 0:
854 854 statprof.reset(freq)
855 855 else:
856 856 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
857 857
858 858 statprof.start()
859 859 try:
860 860 return func()
861 861 finally:
862 862 statprof.stop()
863 863 statprof.display(fp)
864 864
865 865 def _runcommand(ui, options, cmd, cmdfunc):
866 866 def checkargs():
867 867 try:
868 868 return cmdfunc()
869 869 except error.SignatureError:
870 870 raise error.CommandError(cmd, _("invalid arguments"))
871 871
872 872 if options['profile']:
873 873 profiler = os.getenv('HGPROF')
874 874 if profiler is None:
875 875 profiler = ui.config('profiling', 'type', default='ls')
876 876 if profiler not in ('ls', 'stat'):
877 877 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
878 878 profiler = 'ls'
879 879
880 880 output = ui.config('profiling', 'output')
881 881
882 882 if output:
883 883 path = ui.expandpath(output)
884 884 fp = open(path, 'wb')
885 885 else:
886 886 fp = sys.stderr
887 887
888 888 try:
889 889 if profiler == 'ls':
890 890 return lsprofile(ui, checkargs, fp)
891 891 else:
892 892 return statprofile(ui, checkargs, fp)
893 893 finally:
894 894 if output:
895 895 fp.close()
896 896 else:
897 897 return checkargs()
@@ -1,836 +1,836 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 or any later version.
7 7
8 8 from i18n import _
9 9 import errno, getpass, os, socket, sys, tempfile, traceback
10 10 import config, scmutil, util, error, formatter
11 11 from node import hex
12 12
13 13 class ui(object):
14 14 def __init__(self, src=None):
15 15 self._buffers = []
16 16 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
17 17 self._reportuntrusted = True
18 18 self._ocfg = config.config() # overlay
19 19 self._tcfg = config.config() # trusted
20 20 self._ucfg = config.config() # untrusted
21 21 self._trustusers = set()
22 22 self._trustgroups = set()
23 23 self.callhooks = True
24 24
25 25 if src:
26 26 self.fout = src.fout
27 27 self.ferr = src.ferr
28 28 self.fin = src.fin
29 29
30 30 self._tcfg = src._tcfg.copy()
31 31 self._ucfg = src._ucfg.copy()
32 32 self._ocfg = src._ocfg.copy()
33 33 self._trustusers = src._trustusers.copy()
34 34 self._trustgroups = src._trustgroups.copy()
35 35 self.environ = src.environ
36 36 self.callhooks = src.callhooks
37 37 self.fixconfig()
38 38 else:
39 39 self.fout = sys.stdout
40 40 self.ferr = sys.stderr
41 41 self.fin = sys.stdin
42 42
43 43 # shared read-only environment
44 44 self.environ = os.environ
45 45 # we always trust global config files
46 46 for f in scmutil.rcpath():
47 47 self.readconfig(f, trust=True)
48 48
49 49 def copy(self):
50 50 return self.__class__(self)
51 51
52 52 def formatter(self, topic, opts):
53 53 return formatter.formatter(self, topic, opts)
54 54
55 55 def _trusted(self, fp, f):
56 56 st = util.fstat(fp)
57 57 if util.isowner(st):
58 58 return True
59 59
60 60 tusers, tgroups = self._trustusers, self._trustgroups
61 61 if '*' in tusers or '*' in tgroups:
62 62 return True
63 63
64 64 user = util.username(st.st_uid)
65 65 group = util.groupname(st.st_gid)
66 66 if user in tusers or group in tgroups or user == util.username():
67 67 return True
68 68
69 69 if self._reportuntrusted:
70 70 self.warn(_('not trusting file %s from untrusted '
71 71 'user %s, group %s\n') % (f, user, group))
72 72 return False
73 73
74 74 def readconfig(self, filename, root=None, trust=False,
75 75 sections=None, remap=None):
76 76 try:
77 77 fp = open(filename)
78 78 except IOError:
79 79 if not sections: # ignore unless we were looking for something
80 80 return
81 81 raise
82 82
83 83 cfg = config.config()
84 84 trusted = sections or trust or self._trusted(fp, filename)
85 85
86 86 try:
87 87 cfg.read(filename, fp, sections=sections, remap=remap)
88 88 fp.close()
89 89 except error.ConfigError, inst:
90 90 if trusted:
91 91 raise
92 92 self.warn(_("ignored: %s\n") % str(inst))
93 93
94 94 if self.plain():
95 95 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
96 96 'logtemplate', 'style',
97 97 'traceback', 'verbose'):
98 98 if k in cfg['ui']:
99 99 del cfg['ui'][k]
100 100 for k, v in cfg.items('defaults'):
101 101 del cfg['defaults'][k]
102 102 # Don't remove aliases from the configuration if in the exceptionlist
103 103 if self.plain('alias'):
104 104 for k, v in cfg.items('alias'):
105 105 del cfg['alias'][k]
106 106
107 107 if trusted:
108 108 self._tcfg.update(cfg)
109 109 self._tcfg.update(self._ocfg)
110 110 self._ucfg.update(cfg)
111 111 self._ucfg.update(self._ocfg)
112 112
113 113 if root is None:
114 114 root = os.path.expanduser('~')
115 115 self.fixconfig(root=root)
116 116
117 117 def fixconfig(self, root=None, section=None):
118 118 if section in (None, 'paths'):
119 119 # expand vars and ~
120 120 # translate paths relative to root (or home) into absolute paths
121 121 root = root or os.getcwd()
122 122 for c in self._tcfg, self._ucfg, self._ocfg:
123 123 for n, p in c.items('paths'):
124 124 if not p:
125 125 continue
126 126 if '%%' in p:
127 127 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
128 128 % (n, p, self.configsource('paths', n)))
129 129 p = p.replace('%%', '%')
130 130 p = util.expandpath(p)
131 131 if not util.hasscheme(p) and not os.path.isabs(p):
132 132 p = os.path.normpath(os.path.join(root, p))
133 133 c.set("paths", n, p)
134 134
135 135 if section in (None, 'ui'):
136 136 # update ui options
137 137 self.debugflag = self.configbool('ui', 'debug')
138 138 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
139 139 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
140 140 if self.verbose and self.quiet:
141 141 self.quiet = self.verbose = False
142 142 self._reportuntrusted = self.debugflag or self.configbool("ui",
143 143 "report_untrusted", True)
144 144 self.tracebackflag = self.configbool('ui', 'traceback', False)
145 145
146 146 if section in (None, 'trusted'):
147 147 # update trust information
148 148 self._trustusers.update(self.configlist('trusted', 'users'))
149 149 self._trustgroups.update(self.configlist('trusted', 'groups'))
150 150
151 151 def backupconfig(self, section, item):
152 152 return (self._ocfg.backup(section, item),
153 153 self._tcfg.backup(section, item),
154 154 self._ucfg.backup(section, item),)
155 155 def restoreconfig(self, data):
156 156 self._ocfg.restore(data[0])
157 157 self._tcfg.restore(data[1])
158 158 self._ucfg.restore(data[2])
159 159
160 def setconfig(self, section, name, value):
160 def setconfig(self, section, name, value, source=''):
161 161 for cfg in (self._ocfg, self._tcfg, self._ucfg):
162 cfg.set(section, name, value)
162 cfg.set(section, name, value, source)
163 163 self.fixconfig(section=section)
164 164
165 165 def _data(self, untrusted):
166 166 return untrusted and self._ucfg or self._tcfg
167 167
168 168 def configsource(self, section, name, untrusted=False):
169 169 return self._data(untrusted).source(section, name) or 'none'
170 170
171 171 def config(self, section, name, default=None, untrusted=False):
172 172 if isinstance(name, list):
173 173 alternates = name
174 174 else:
175 175 alternates = [name]
176 176
177 177 for n in alternates:
178 178 value = self._data(untrusted).get(section, n, None)
179 179 if value is not None:
180 180 name = n
181 181 break
182 182 else:
183 183 value = default
184 184
185 185 if self.debugflag and not untrusted and self._reportuntrusted:
186 186 for n in alternates:
187 187 uvalue = self._ucfg.get(section, n)
188 188 if uvalue is not None and uvalue != value:
189 189 self.debug("ignoring untrusted configuration option "
190 190 "%s.%s = %s\n" % (section, n, uvalue))
191 191 return value
192 192
193 193 def configpath(self, section, name, default=None, untrusted=False):
194 194 'get a path config item, expanded relative to repo root or config file'
195 195 v = self.config(section, name, default, untrusted)
196 196 if v is None:
197 197 return None
198 198 if not os.path.isabs(v) or "://" not in v:
199 199 src = self.configsource(section, name, untrusted)
200 200 if ':' in src:
201 201 base = os.path.dirname(src.rsplit(':')[0])
202 202 v = os.path.join(base, os.path.expanduser(v))
203 203 return v
204 204
205 205 def configbool(self, section, name, default=False, untrusted=False):
206 206 """parse a configuration element as a boolean
207 207
208 208 >>> u = ui(); s = 'foo'
209 209 >>> u.setconfig(s, 'true', 'yes')
210 210 >>> u.configbool(s, 'true')
211 211 True
212 212 >>> u.setconfig(s, 'false', 'no')
213 213 >>> u.configbool(s, 'false')
214 214 False
215 215 >>> u.configbool(s, 'unknown')
216 216 False
217 217 >>> u.configbool(s, 'unknown', True)
218 218 True
219 219 >>> u.setconfig(s, 'invalid', 'somevalue')
220 220 >>> u.configbool(s, 'invalid')
221 221 Traceback (most recent call last):
222 222 ...
223 223 ConfigError: foo.invalid is not a boolean ('somevalue')
224 224 """
225 225
226 226 v = self.config(section, name, None, untrusted)
227 227 if v is None:
228 228 return default
229 229 if isinstance(v, bool):
230 230 return v
231 231 b = util.parsebool(v)
232 232 if b is None:
233 233 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
234 234 % (section, name, v))
235 235 return b
236 236
237 237 def configint(self, section, name, default=None, untrusted=False):
238 238 """parse a configuration element as an integer
239 239
240 240 >>> u = ui(); s = 'foo'
241 241 >>> u.setconfig(s, 'int1', '42')
242 242 >>> u.configint(s, 'int1')
243 243 42
244 244 >>> u.setconfig(s, 'int2', '-42')
245 245 >>> u.configint(s, 'int2')
246 246 -42
247 247 >>> u.configint(s, 'unknown', 7)
248 248 7
249 249 >>> u.setconfig(s, 'invalid', 'somevalue')
250 250 >>> u.configint(s, 'invalid')
251 251 Traceback (most recent call last):
252 252 ...
253 253 ConfigError: foo.invalid is not an integer ('somevalue')
254 254 """
255 255
256 256 v = self.config(section, name, None, untrusted)
257 257 if v is None:
258 258 return default
259 259 try:
260 260 return int(v)
261 261 except ValueError:
262 262 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
263 263 % (section, name, v))
264 264
265 265 def configbytes(self, section, name, default=0, untrusted=False):
266 266 """parse a configuration element as a quantity in bytes
267 267
268 268 Units can be specified as b (bytes), k or kb (kilobytes), m or
269 269 mb (megabytes), g or gb (gigabytes).
270 270
271 271 >>> u = ui(); s = 'foo'
272 272 >>> u.setconfig(s, 'val1', '42')
273 273 >>> u.configbytes(s, 'val1')
274 274 42
275 275 >>> u.setconfig(s, 'val2', '42.5 kb')
276 276 >>> u.configbytes(s, 'val2')
277 277 43520
278 278 >>> u.configbytes(s, 'unknown', '7 MB')
279 279 7340032
280 280 >>> u.setconfig(s, 'invalid', 'somevalue')
281 281 >>> u.configbytes(s, 'invalid')
282 282 Traceback (most recent call last):
283 283 ...
284 284 ConfigError: foo.invalid is not a byte quantity ('somevalue')
285 285 """
286 286
287 287 value = self.config(section, name)
288 288 if value is None:
289 289 if not isinstance(default, str):
290 290 return default
291 291 value = default
292 292 try:
293 293 return util.sizetoint(value)
294 294 except error.ParseError:
295 295 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
296 296 % (section, name, value))
297 297
298 298 def configlist(self, section, name, default=None, untrusted=False):
299 299 """parse a configuration element as a list of comma/space separated
300 300 strings
301 301
302 302 >>> u = ui(); s = 'foo'
303 303 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
304 304 >>> u.configlist(s, 'list1')
305 305 ['this', 'is', 'a small', 'test']
306 306 """
307 307
308 308 def _parse_plain(parts, s, offset):
309 309 whitespace = False
310 310 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
311 311 whitespace = True
312 312 offset += 1
313 313 if offset >= len(s):
314 314 return None, parts, offset
315 315 if whitespace:
316 316 parts.append('')
317 317 if s[offset] == '"' and not parts[-1]:
318 318 return _parse_quote, parts, offset + 1
319 319 elif s[offset] == '"' and parts[-1][-1] == '\\':
320 320 parts[-1] = parts[-1][:-1] + s[offset]
321 321 return _parse_plain, parts, offset + 1
322 322 parts[-1] += s[offset]
323 323 return _parse_plain, parts, offset + 1
324 324
325 325 def _parse_quote(parts, s, offset):
326 326 if offset < len(s) and s[offset] == '"': # ""
327 327 parts.append('')
328 328 offset += 1
329 329 while offset < len(s) and (s[offset].isspace() or
330 330 s[offset] == ','):
331 331 offset += 1
332 332 return _parse_plain, parts, offset
333 333
334 334 while offset < len(s) and s[offset] != '"':
335 335 if (s[offset] == '\\' and offset + 1 < len(s)
336 336 and s[offset + 1] == '"'):
337 337 offset += 1
338 338 parts[-1] += '"'
339 339 else:
340 340 parts[-1] += s[offset]
341 341 offset += 1
342 342
343 343 if offset >= len(s):
344 344 real_parts = _configlist(parts[-1])
345 345 if not real_parts:
346 346 parts[-1] = '"'
347 347 else:
348 348 real_parts[0] = '"' + real_parts[0]
349 349 parts = parts[:-1]
350 350 parts.extend(real_parts)
351 351 return None, parts, offset
352 352
353 353 offset += 1
354 354 while offset < len(s) and s[offset] in [' ', ',']:
355 355 offset += 1
356 356
357 357 if offset < len(s):
358 358 if offset + 1 == len(s) and s[offset] == '"':
359 359 parts[-1] += '"'
360 360 offset += 1
361 361 else:
362 362 parts.append('')
363 363 else:
364 364 return None, parts, offset
365 365
366 366 return _parse_plain, parts, offset
367 367
368 368 def _configlist(s):
369 369 s = s.rstrip(' ,')
370 370 if not s:
371 371 return []
372 372 parser, parts, offset = _parse_plain, [''], 0
373 373 while parser:
374 374 parser, parts, offset = parser(parts, s, offset)
375 375 return parts
376 376
377 377 result = self.config(section, name, untrusted=untrusted)
378 378 if result is None:
379 379 result = default or []
380 380 if isinstance(result, basestring):
381 381 result = _configlist(result.lstrip(' ,\n'))
382 382 if result is None:
383 383 result = default or []
384 384 return result
385 385
386 386 def has_section(self, section, untrusted=False):
387 387 '''tell whether section exists in config.'''
388 388 return section in self._data(untrusted)
389 389
390 390 def configitems(self, section, untrusted=False):
391 391 items = self._data(untrusted).items(section)
392 392 if self.debugflag and not untrusted and self._reportuntrusted:
393 393 for k, v in self._ucfg.items(section):
394 394 if self._tcfg.get(section, k) != v:
395 395 self.debug("ignoring untrusted configuration option "
396 396 "%s.%s = %s\n" % (section, k, v))
397 397 return items
398 398
399 399 def walkconfig(self, untrusted=False):
400 400 cfg = self._data(untrusted)
401 401 for section in cfg.sections():
402 402 for name, value in self.configitems(section, untrusted):
403 403 yield section, name, value
404 404
405 405 def plain(self, feature=None):
406 406 '''is plain mode active?
407 407
408 408 Plain mode means that all configuration variables which affect
409 409 the behavior and output of Mercurial should be
410 410 ignored. Additionally, the output should be stable,
411 411 reproducible and suitable for use in scripts or applications.
412 412
413 413 The only way to trigger plain mode is by setting either the
414 414 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
415 415
416 416 The return value can either be
417 417 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
418 418 - True otherwise
419 419 '''
420 420 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
421 421 return False
422 422 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
423 423 if feature and exceptions:
424 424 return feature not in exceptions
425 425 return True
426 426
427 427 def username(self):
428 428 """Return default username to be used in commits.
429 429
430 430 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
431 431 and stop searching if one of these is set.
432 432 If not found and ui.askusername is True, ask the user, else use
433 433 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
434 434 """
435 435 user = os.environ.get("HGUSER")
436 436 if user is None:
437 437 user = self.config("ui", "username")
438 438 if user is not None:
439 439 user = os.path.expandvars(user)
440 440 if user is None:
441 441 user = os.environ.get("EMAIL")
442 442 if user is None and self.configbool("ui", "askusername"):
443 443 user = self.prompt(_("enter a commit username:"), default=None)
444 444 if user is None and not self.interactive():
445 445 try:
446 446 user = '%s@%s' % (util.getuser(), socket.getfqdn())
447 447 self.warn(_("no username found, using '%s' instead\n") % user)
448 448 except KeyError:
449 449 pass
450 450 if not user:
451 451 raise util.Abort(_('no username supplied'),
452 452 hint=_('use "hg config --edit" '
453 453 'to set your username'))
454 454 if "\n" in user:
455 455 raise util.Abort(_("username %s contains a newline\n") % repr(user))
456 456 return user
457 457
458 458 def shortuser(self, user):
459 459 """Return a short representation of a user name or email address."""
460 460 if not self.verbose:
461 461 user = util.shortuser(user)
462 462 return user
463 463
464 464 def expandpath(self, loc, default=None):
465 465 """Return repository location relative to cwd or from [paths]"""
466 466 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
467 467 return loc
468 468
469 469 path = self.config('paths', loc)
470 470 if not path and default is not None:
471 471 path = self.config('paths', default)
472 472 return path or loc
473 473
474 474 def pushbuffer(self):
475 475 self._buffers.append([])
476 476
477 477 def popbuffer(self, labeled=False):
478 478 '''pop the last buffer and return the buffered output
479 479
480 480 If labeled is True, any labels associated with buffered
481 481 output will be handled. By default, this has no effect
482 482 on the output returned, but extensions and GUI tools may
483 483 handle this argument and returned styled output. If output
484 484 is being buffered so it can be captured and parsed or
485 485 processed, labeled should not be set to True.
486 486 '''
487 487 return "".join(self._buffers.pop())
488 488
489 489 def write(self, *args, **opts):
490 490 '''write args to output
491 491
492 492 By default, this method simply writes to the buffer or stdout,
493 493 but extensions or GUI tools may override this method,
494 494 write_err(), popbuffer(), and label() to style output from
495 495 various parts of hg.
496 496
497 497 An optional keyword argument, "label", can be passed in.
498 498 This should be a string containing label names separated by
499 499 space. Label names take the form of "topic.type". For example,
500 500 ui.debug() issues a label of "ui.debug".
501 501
502 502 When labeling output for a specific command, a label of
503 503 "cmdname.type" is recommended. For example, status issues
504 504 a label of "status.modified" for modified files.
505 505 '''
506 506 if self._buffers:
507 507 self._buffers[-1].extend([str(a) for a in args])
508 508 else:
509 509 for a in args:
510 510 self.fout.write(str(a))
511 511
512 512 def write_err(self, *args, **opts):
513 513 try:
514 514 if not getattr(self.fout, 'closed', False):
515 515 self.fout.flush()
516 516 for a in args:
517 517 self.ferr.write(str(a))
518 518 # stderr may be buffered under win32 when redirected to files,
519 519 # including stdout.
520 520 if not getattr(self.ferr, 'closed', False):
521 521 self.ferr.flush()
522 522 except IOError, inst:
523 523 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
524 524 raise
525 525
526 526 def flush(self):
527 527 try: self.fout.flush()
528 528 except (IOError, ValueError): pass
529 529 try: self.ferr.flush()
530 530 except (IOError, ValueError): pass
531 531
532 532 def _isatty(self, fh):
533 533 if self.configbool('ui', 'nontty', False):
534 534 return False
535 535 return util.isatty(fh)
536 536
537 537 def interactive(self):
538 538 '''is interactive input allowed?
539 539
540 540 An interactive session is a session where input can be reasonably read
541 541 from `sys.stdin'. If this function returns false, any attempt to read
542 542 from stdin should fail with an error, unless a sensible default has been
543 543 specified.
544 544
545 545 Interactiveness is triggered by the value of the `ui.interactive'
546 546 configuration variable or - if it is unset - when `sys.stdin' points
547 547 to a terminal device.
548 548
549 549 This function refers to input only; for output, see `ui.formatted()'.
550 550 '''
551 551 i = self.configbool("ui", "interactive", None)
552 552 if i is None:
553 553 # some environments replace stdin without implementing isatty
554 554 # usually those are non-interactive
555 555 return self._isatty(self.fin)
556 556
557 557 return i
558 558
559 559 def termwidth(self):
560 560 '''how wide is the terminal in columns?
561 561 '''
562 562 if 'COLUMNS' in os.environ:
563 563 try:
564 564 return int(os.environ['COLUMNS'])
565 565 except ValueError:
566 566 pass
567 567 return util.termwidth()
568 568
569 569 def formatted(self):
570 570 '''should formatted output be used?
571 571
572 572 It is often desirable to format the output to suite the output medium.
573 573 Examples of this are truncating long lines or colorizing messages.
574 574 However, this is not often not desirable when piping output into other
575 575 utilities, e.g. `grep'.
576 576
577 577 Formatted output is triggered by the value of the `ui.formatted'
578 578 configuration variable or - if it is unset - when `sys.stdout' points
579 579 to a terminal device. Please note that `ui.formatted' should be
580 580 considered an implementation detail; it is not intended for use outside
581 581 Mercurial or its extensions.
582 582
583 583 This function refers to output only; for input, see `ui.interactive()'.
584 584 This function always returns false when in plain mode, see `ui.plain()'.
585 585 '''
586 586 if self.plain():
587 587 return False
588 588
589 589 i = self.configbool("ui", "formatted", None)
590 590 if i is None:
591 591 # some environments replace stdout without implementing isatty
592 592 # usually those are non-interactive
593 593 return self._isatty(self.fout)
594 594
595 595 return i
596 596
597 597 def _readline(self, prompt=''):
598 598 if self._isatty(self.fin):
599 599 try:
600 600 # magically add command line editing support, where
601 601 # available
602 602 import readline
603 603 # force demandimport to really load the module
604 604 readline.read_history_file
605 605 # windows sometimes raises something other than ImportError
606 606 except Exception:
607 607 pass
608 608
609 609 # call write() so output goes through subclassed implementation
610 610 # e.g. color extension on Windows
611 611 self.write(prompt)
612 612
613 613 # instead of trying to emulate raw_input, swap (self.fin,
614 614 # self.fout) with (sys.stdin, sys.stdout)
615 615 oldin = sys.stdin
616 616 oldout = sys.stdout
617 617 sys.stdin = self.fin
618 618 sys.stdout = self.fout
619 619 line = raw_input(' ')
620 620 sys.stdin = oldin
621 621 sys.stdout = oldout
622 622
623 623 # When stdin is in binary mode on Windows, it can cause
624 624 # raw_input() to emit an extra trailing carriage return
625 625 if os.linesep == '\r\n' and line and line[-1] == '\r':
626 626 line = line[:-1]
627 627 return line
628 628
629 629 def prompt(self, msg, default="y"):
630 630 """Prompt user with msg, read response.
631 631 If ui is not interactive, the default is returned.
632 632 """
633 633 if not self.interactive():
634 634 self.write(msg, ' ', default, "\n")
635 635 return default
636 636 try:
637 637 r = self._readline(self.label(msg, 'ui.prompt'))
638 638 if not r:
639 639 return default
640 640 return r
641 641 except EOFError:
642 642 raise util.Abort(_('response expected'))
643 643
644 644 @staticmethod
645 645 def extractchoices(prompt):
646 646 """Extract prompt message and list of choices from specified prompt.
647 647
648 648 This returns tuple "(message, choices)", and "choices" is the
649 649 list of tuple "(response character, text without &)".
650 650 """
651 651 parts = prompt.split('$$')
652 652 msg = parts[0].rstrip(' ')
653 653 choices = [p.strip(' ') for p in parts[1:]]
654 654 return (msg,
655 655 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
656 656 for s in choices])
657 657
658 658 def promptchoice(self, prompt, default=0):
659 659 """Prompt user with a message, read response, and ensure it matches
660 660 one of the provided choices. The prompt is formatted as follows:
661 661
662 662 "would you like fries with that (Yn)? $$ &Yes $$ &No"
663 663
664 664 The index of the choice is returned. Responses are case
665 665 insensitive. If ui is not interactive, the default is
666 666 returned.
667 667 """
668 668
669 669 msg, choices = self.extractchoices(prompt)
670 670 resps = [r for r, t in choices]
671 671 while True:
672 672 r = self.prompt(msg, resps[default])
673 673 if r.lower() in resps:
674 674 return resps.index(r.lower())
675 675 self.write(_("unrecognized response\n"))
676 676
677 677 def getpass(self, prompt=None, default=None):
678 678 if not self.interactive():
679 679 return default
680 680 try:
681 681 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
682 682 return getpass.getpass('')
683 683 except EOFError:
684 684 raise util.Abort(_('response expected'))
685 685 def status(self, *msg, **opts):
686 686 '''write status message to output (if ui.quiet is False)
687 687
688 688 This adds an output label of "ui.status".
689 689 '''
690 690 if not self.quiet:
691 691 opts['label'] = opts.get('label', '') + ' ui.status'
692 692 self.write(*msg, **opts)
693 693 def warn(self, *msg, **opts):
694 694 '''write warning message to output (stderr)
695 695
696 696 This adds an output label of "ui.warning".
697 697 '''
698 698 opts['label'] = opts.get('label', '') + ' ui.warning'
699 699 self.write_err(*msg, **opts)
700 700 def note(self, *msg, **opts):
701 701 '''write note to output (if ui.verbose is True)
702 702
703 703 This adds an output label of "ui.note".
704 704 '''
705 705 if self.verbose:
706 706 opts['label'] = opts.get('label', '') + ' ui.note'
707 707 self.write(*msg, **opts)
708 708 def debug(self, *msg, **opts):
709 709 '''write debug message to output (if ui.debugflag is True)
710 710
711 711 This adds an output label of "ui.debug".
712 712 '''
713 713 if self.debugflag:
714 714 opts['label'] = opts.get('label', '') + ' ui.debug'
715 715 self.write(*msg, **opts)
716 716 def edit(self, text, user, extra={}):
717 717 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
718 718 text=True)
719 719 try:
720 720 f = os.fdopen(fd, "w")
721 721 f.write(text)
722 722 f.close()
723 723
724 724 environ = {'HGUSER': user}
725 725 if 'transplant_source' in extra:
726 726 environ.update({'HGREVISION': hex(extra['transplant_source'])})
727 727 for label in ('source', 'rebase_source'):
728 728 if label in extra:
729 729 environ.update({'HGREVISION': extra[label]})
730 730 break
731 731
732 732 editor = self.geteditor()
733 733
734 734 util.system("%s \"%s\"" % (editor, name),
735 735 environ=environ,
736 736 onerr=util.Abort, errprefix=_("edit failed"),
737 737 out=self.fout)
738 738
739 739 f = open(name)
740 740 t = f.read()
741 741 f.close()
742 742 finally:
743 743 os.unlink(name)
744 744
745 745 return t
746 746
747 747 def traceback(self, exc=None, force=False):
748 748 '''print exception traceback if traceback printing enabled or forced.
749 749 only to call in exception handler. returns true if traceback
750 750 printed.'''
751 751 if self.tracebackflag or force:
752 752 if exc is None:
753 753 exc = sys.exc_info()
754 754 cause = getattr(exc[1], 'cause', None)
755 755
756 756 if cause is not None:
757 757 causetb = traceback.format_tb(cause[2])
758 758 exctb = traceback.format_tb(exc[2])
759 759 exconly = traceback.format_exception_only(cause[0], cause[1])
760 760
761 761 # exclude frame where 'exc' was chained and rethrown from exctb
762 762 self.write_err('Traceback (most recent call last):\n',
763 763 ''.join(exctb[:-1]),
764 764 ''.join(causetb),
765 765 ''.join(exconly))
766 766 else:
767 767 traceback.print_exception(exc[0], exc[1], exc[2],
768 768 file=self.ferr)
769 769 return self.tracebackflag or force
770 770
771 771 def geteditor(self):
772 772 '''return editor to use'''
773 773 if sys.platform == 'plan9':
774 774 # vi is the MIPS instruction simulator on Plan 9. We
775 775 # instead default to E to plumb commit messages to
776 776 # avoid confusion.
777 777 editor = 'E'
778 778 else:
779 779 editor = 'vi'
780 780 return (os.environ.get("HGEDITOR") or
781 781 self.config("ui", "editor") or
782 782 os.environ.get("VISUAL") or
783 783 os.environ.get("EDITOR", editor))
784 784
785 785 def progress(self, topic, pos, item="", unit="", total=None):
786 786 '''show a progress message
787 787
788 788 With stock hg, this is simply a debug message that is hidden
789 789 by default, but with extensions or GUI tools it may be
790 790 visible. 'topic' is the current operation, 'item' is a
791 791 non-numeric marker of the current position (i.e. the currently
792 792 in-process file), 'pos' is the current numeric position (i.e.
793 793 revision, bytes, etc.), unit is a corresponding unit label,
794 794 and total is the highest expected pos.
795 795
796 796 Multiple nested topics may be active at a time.
797 797
798 798 All topics should be marked closed by setting pos to None at
799 799 termination.
800 800 '''
801 801
802 802 if pos is None or not self.debugflag:
803 803 return
804 804
805 805 if unit:
806 806 unit = ' ' + unit
807 807 if item:
808 808 item = ' ' + item
809 809
810 810 if total:
811 811 pct = 100.0 * pos / total
812 812 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
813 813 % (topic, item, pos, total, unit, pct))
814 814 else:
815 815 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
816 816
817 817 def log(self, service, *msg, **opts):
818 818 '''hook for logging facility extensions
819 819
820 820 service should be a readily-identifiable subsystem, which will
821 821 allow filtering.
822 822 message should be a newline-terminated string to log.
823 823 '''
824 824 pass
825 825
826 826 def label(self, msg, label):
827 827 '''style msg based on supplied label
828 828
829 829 Like ui.write(), this just returns msg unchanged, but extensions
830 830 and GUI tools can override it to allow styling output without
831 831 writing it.
832 832
833 833 ui.write(s, 'label') is equivalent to
834 834 ui.write(ui.label(s, 'label')).
835 835 '''
836 836 return msg
@@ -1,203 +1,203 b''
1 1 hide outer repo
2 2 $ hg init
3 3
4 4 Use hgrc within $TESTTMP
5 5
6 6 $ HGRCPATH=`pwd`/hgrc
7 7 $ export HGRCPATH
8 8
9 9 Use an alternate var for scribbling on hgrc to keep check-code from
10 10 complaining about the important settings we may be overwriting:
11 11
12 12 $ HGRC=`pwd`/hgrc
13 13 $ export HGRC
14 14
15 15 Basic syntax error
16 16
17 17 $ echo "invalid" > $HGRC
18 18 $ hg version
19 19 hg: parse error at $TESTTMP/hgrc:1: invalid
20 20 [255]
21 21 $ echo "" > $HGRC
22 22
23 23 Issue1199: Can't use '%' in hgrc (eg url encoded username)
24 24
25 25 $ hg init "foo%bar"
26 26 $ hg clone "foo%bar" foobar
27 27 updating to branch default
28 28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 29 $ cd foobar
30 30 $ cat .hg/hgrc
31 31 [paths]
32 32 default = $TESTTMP/foo%bar (glob)
33 33 $ hg paths
34 34 default = $TESTTMP/foo%bar (glob)
35 35 $ hg showconfig
36 36 bundle.mainreporoot=$TESTTMP/foobar (glob)
37 37 paths.default=$TESTTMP/foo%bar (glob)
38 38 $ cd ..
39 39
40 40 issue1829: wrong indentation
41 41
42 42 $ echo '[foo]' > $HGRC
43 43 $ echo ' x = y' >> $HGRC
44 44 $ hg version
45 45 hg: parse error at $TESTTMP/hgrc:2: x = y
46 46 [255]
47 47
48 48 $ python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
49 49 > > $HGRC
50 50 $ hg showconfig foo
51 51 foo.bar=a\nb\nc\nde\nfg
52 52 foo.baz=bif cb
53 53
54 54 $ FAKEPATH=/path/to/nowhere
55 55 $ export FAKEPATH
56 56 $ echo '%include $FAKEPATH/no-such-file' > $HGRC
57 57 $ hg version
58 58 Mercurial Distributed SCM (version *) (glob)
59 59 (see http://mercurial.selenic.com for more information)
60 60
61 61 Copyright (C) 2005-2014 Matt Mackall and others
62 62 This is free software; see the source for copying conditions. There is NO
63 63 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
64 64 $ unset FAKEPATH
65 65
66 66 make sure global options given on the cmdline take precedence
67 67
68 68 $ hg showconfig --config ui.verbose=True --quiet
69 69 bundle.mainreporoot=$TESTTMP
70 70 ui.verbose=False
71 71 ui.debug=False
72 72 ui.quiet=True
73 73
74 74 $ touch foobar/untracked
75 75 $ cat >> foobar/.hg/hgrc <<EOF
76 76 > [ui]
77 77 > verbose=True
78 78 > EOF
79 79 $ hg -R foobar st -q
80 80
81 81 username expansion
82 82
83 83 $ olduser=$HGUSER
84 84 $ unset HGUSER
85 85
86 86 $ FAKEUSER='John Doe'
87 87 $ export FAKEUSER
88 88 $ echo '[ui]' > $HGRC
89 89 $ echo 'username = $FAKEUSER' >> $HGRC
90 90
91 91 $ hg init usertest
92 92 $ cd usertest
93 93 $ touch bar
94 94 $ hg commit --addremove --quiet -m "added bar"
95 95 $ hg log --template "{author}\n"
96 96 John Doe
97 97 $ cd ..
98 98
99 99 $ hg showconfig
100 100 bundle.mainreporoot=$TESTTMP
101 101 ui.username=$FAKEUSER
102 102
103 103 $ unset FAKEUSER
104 104 $ HGUSER=$olduser
105 105 $ export HGUSER
106 106
107 107 showconfig with multiple arguments
108 108
109 109 $ echo "[alias]" > $HGRC
110 110 $ echo "log = log -g" >> $HGRC
111 111 $ echo "[defaults]" >> $HGRC
112 112 $ echo "identify = -n" >> $HGRC
113 113 $ hg showconfig alias defaults
114 114 alias.log=log -g
115 115 defaults.identify=-n
116 116 $ hg showconfig alias defaults.identify
117 117 abort: only one config item permitted
118 118 [255]
119 119 $ hg showconfig alias.log defaults.identify
120 120 abort: only one config item permitted
121 121 [255]
122 122
123 123 HGPLAIN
124 124
125 125 $ echo "[ui]" > $HGRC
126 126 $ echo "debug=true" >> $HGRC
127 127 $ echo "fallbackencoding=ASCII" >> $HGRC
128 128 $ echo "quiet=true" >> $HGRC
129 129 $ echo "slash=true" >> $HGRC
130 130 $ echo "traceback=true" >> $HGRC
131 131 $ echo "verbose=true" >> $HGRC
132 132 $ echo "style=~/.hgstyle" >> $HGRC
133 133 $ echo "logtemplate={node}" >> $HGRC
134 134 $ echo "[defaults]" >> $HGRC
135 135 $ echo "identify=-n" >> $HGRC
136 136 $ echo "[alias]" >> $HGRC
137 137 $ echo "log=log -g" >> $HGRC
138 138
139 139 customized hgrc
140 140
141 141 $ hg showconfig
142 142 read config from: $TESTTMP/hgrc
143 143 $TESTTMP/hgrc:13: alias.log=log -g
144 none: bundle.mainreporoot=$TESTTMP
144 repo: bundle.mainreporoot=$TESTTMP
145 145 $TESTTMP/hgrc:11: defaults.identify=-n
146 146 $TESTTMP/hgrc:2: ui.debug=true
147 147 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
148 148 $TESTTMP/hgrc:4: ui.quiet=true
149 149 $TESTTMP/hgrc:5: ui.slash=true
150 150 $TESTTMP/hgrc:6: ui.traceback=true
151 151 $TESTTMP/hgrc:7: ui.verbose=true
152 152 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
153 153 $TESTTMP/hgrc:9: ui.logtemplate={node}
154 154
155 155 plain hgrc
156 156
157 157 $ HGPLAIN=; export HGPLAIN
158 158 $ hg showconfig --config ui.traceback=True --debug
159 159 read config from: $TESTTMP/hgrc
160 none: bundle.mainreporoot=$TESTTMP
161 none: ui.traceback=True
162 none: ui.verbose=False
163 none: ui.debug=True
164 none: ui.quiet=False
160 repo: bundle.mainreporoot=$TESTTMP
161 --config: ui.traceback=True
162 --verbose: ui.verbose=False
163 --debug: ui.debug=True
164 --quiet: ui.quiet=False
165 165
166 166 plain mode with exceptions
167 167
168 168 $ cat > plain.py <<EOF
169 169 > def uisetup(ui):
170 170 > ui.write('plain: %r\n' % ui.plain())
171 171 > EOF
172 172 $ echo "[extensions]" >> $HGRC
173 173 $ echo "plain=./plain.py" >> $HGRC
174 174 $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
175 175 $ hg showconfig --config ui.traceback=True --debug
176 176 plain: True
177 177 read config from: $TESTTMP/hgrc
178 none: bundle.mainreporoot=$TESTTMP
178 repo: bundle.mainreporoot=$TESTTMP
179 179 $TESTTMP/hgrc:15: extensions.plain=./plain.py
180 none: ui.traceback=True
181 none: ui.verbose=False
182 none: ui.debug=True
183 none: ui.quiet=False
180 --config: ui.traceback=True
181 --verbose: ui.verbose=False
182 --debug: ui.debug=True
183 --quiet: ui.quiet=False
184 184 $ unset HGPLAIN
185 185 $ hg showconfig --config ui.traceback=True --debug
186 186 plain: True
187 187 read config from: $TESTTMP/hgrc
188 none: bundle.mainreporoot=$TESTTMP
188 repo: bundle.mainreporoot=$TESTTMP
189 189 $TESTTMP/hgrc:15: extensions.plain=./plain.py
190 none: ui.traceback=True
191 none: ui.verbose=False
192 none: ui.debug=True
193 none: ui.quiet=False
190 --config: ui.traceback=True
191 --verbose: ui.verbose=False
192 --debug: ui.debug=True
193 --quiet: ui.quiet=False
194 194 $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
195 195 $ hg showconfig --config ui.traceback=True --debug
196 196 plain: True
197 197 read config from: $TESTTMP/hgrc
198 none: bundle.mainreporoot=$TESTTMP
198 repo: bundle.mainreporoot=$TESTTMP
199 199 $TESTTMP/hgrc:15: extensions.plain=./plain.py
200 none: ui.traceback=True
201 none: ui.verbose=False
202 none: ui.debug=True
203 none: ui.quiet=False
200 --config: ui.traceback=True
201 --verbose: ui.verbose=False
202 --debug: ui.debug=True
203 --quiet: ui.quiet=False
General Comments 0
You need to be logged in to leave comments. Login now