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