##// END OF EJS Templates
ui: introduce new config parser
Matt Mackall -
r8144:fca54469 default
parent child Browse files
Show More
@@ -0,0 +1,93 b''
1 from i18n import _
2 import re, error
3
4 class sortdict(dict):
5 'a simple append-only sorted dictionary'
6 def __init__(self, data=None):
7 self._list = []
8 if data:
9 if hasattr(data, '_list'):
10 self._list = list(data._list)
11 self.update(data)
12 def copy(self):
13 return sortdict(self)
14 def __setitem__(self, key, val):
15 if key in self:
16 self._list.remove(key)
17 self._list.append(key)
18 dict.__setitem__(self, key, val)
19 def __iter__(self):
20 return self._list.__iter__()
21 def update(self, src):
22 for k in src:
23 self[k] = src[k]
24 def items(self):
25 return [(k,self[k]) for k in self._list]
26
27 class config:
28 def __init__(self, data=None):
29 self._data = {}
30 if data:
31 for k in data._data:
32 self._data[k] = data[k].copy()
33 def copy(self):
34 return config(self)
35 def __contains__(self, section):
36 return section in self._data
37 def update(self, src, sections=None):
38 if not sections:
39 sections = src.sections()
40 for s in sections:
41 if s not in src:
42 continue
43 if s not in self:
44 self._data[s] = sortdict()
45 for k in src._data[s]:
46 self._data[s][k] = src._data[s][k]
47 def get(self, section, item, default=None):
48 return self._data.get(section, {}).get(item, (default, ""))[0]
49 def getsource(self, section, item):
50 return self._data.get(section, {}).get(item, (None, ""))[1]
51 def sections(self):
52 return sorted(self._data.keys())
53 def items(self, section):
54 return [(k, v[0]) for k,v in self._data.get(section, {}).items()]
55 def set(self, section, item, value, source=""):
56 if section not in self:
57 self._data[section] = sortdict()
58 self._data[section][item] = (value, source)
59
60 def read(self, path, fp):
61 sectionre = re.compile(r'\[([^\[]+)\]')
62 itemre = re.compile(r'([^=\s]+)\s*=\s*(.*)')
63 contre = re.compile(r'\s+(\S.*)')
64 emptyre = re.compile(r'(;|#|\s*$)')
65 section = ""
66 item = None
67 line = 0
68 cont = 0
69 for l in fp:
70 line += 1
71 if cont:
72 m = contre.match(l)
73 if m:
74 v = self.get(section, item) + "\n" + m.group(1)
75 self.set(section, item, v, "%s:%d" % (path, line))
76 continue
77 item = None
78 if emptyre.match(l):
79 continue
80 m = sectionre.match(l)
81 if m:
82 section = m.group(1)
83 if section not in self:
84 self._data[section] = sortdict()
85 continue
86 m = itemre.match(l)
87 if m:
88 item = m.group(1)
89 self.set(section, item, m.group(2), "%s:%d" % (path, line))
90 cont = 1
91 continue
92 raise error.ConfigError(_('config error at %s:%d: \'%s\'')
93 % (path, line, l.rstrip()))
@@ -1,428 +1,430 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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import 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.print_exc()
50 ui.print_exc()
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:
59 ui.warn(_("hg: %s\n") % inst.args[0])
58 except error.LockHeld, inst:
60 except error.LockHeld, inst:
59 if inst.errno == errno.ETIMEDOUT:
61 if inst.errno == errno.ETIMEDOUT:
60 reason = _('timed out waiting for lock held by %s') % inst.locker
62 reason = _('timed out waiting for lock held by %s') % inst.locker
61 else:
63 else:
62 reason = _('lock held by %s') % inst.locker
64 reason = _('lock held by %s') % inst.locker
63 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))
64 except error.LockUnavailable, inst:
66 except error.LockUnavailable, inst:
65 ui.warn(_("abort: could not lock %s: %s\n") %
67 ui.warn(_("abort: could not lock %s: %s\n") %
66 (inst.desc or inst.filename, inst.strerror))
68 (inst.desc or inst.filename, inst.strerror))
67 except error.ParseError, inst:
69 except error.ParseError, inst:
68 if inst.args[0]:
70 if inst.args[0]:
69 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]))
70 commands.help_(ui, inst.args[0])
72 commands.help_(ui, inst.args[0])
71 else:
73 else:
72 ui.warn(_("hg: %s\n") % inst.args[1])
74 ui.warn(_("hg: %s\n") % inst.args[1])
73 commands.help_(ui, 'shortlist')
75 commands.help_(ui, 'shortlist')
74 except error.RepoError, inst:
76 except error.RepoError, inst:
75 ui.warn(_("abort: %s!\n") % inst)
77 ui.warn(_("abort: %s!\n") % inst)
76 except error.ResponseError, inst:
78 except error.ResponseError, inst:
77 ui.warn(_("abort: %s") % inst.args[0])
79 ui.warn(_("abort: %s") % inst.args[0])
78 if not isinstance(inst.args[1], basestring):
80 if not isinstance(inst.args[1], basestring):
79 ui.warn(" %r\n" % (inst.args[1],))
81 ui.warn(" %r\n" % (inst.args[1],))
80 elif not inst.args[1]:
82 elif not inst.args[1]:
81 ui.warn(_(" empty string\n"))
83 ui.warn(_(" empty string\n"))
82 else:
84 else:
83 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
85 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
84 except error.RevlogError, inst:
86 except error.RevlogError, inst:
85 ui.warn(_("abort: %s!\n") % inst)
87 ui.warn(_("abort: %s!\n") % inst)
86 except error.SignalInterrupt:
88 except error.SignalInterrupt:
87 ui.warn(_("killed!\n"))
89 ui.warn(_("killed!\n"))
88 except error.UnknownCommand, inst:
90 except error.UnknownCommand, inst:
89 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
91 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
90 commands.help_(ui, 'shortlist')
92 commands.help_(ui, 'shortlist')
91 except util.Abort, inst:
93 except util.Abort, inst:
92 ui.warn(_("abort: %s\n") % inst)
94 ui.warn(_("abort: %s\n") % inst)
93 except ImportError, inst:
95 except ImportError, inst:
94 m = str(inst).split()[-1]
96 m = str(inst).split()[-1]
95 ui.warn(_("abort: could not import module %s!\n") % m)
97 ui.warn(_("abort: could not import module %s!\n") % m)
96 if m in "mpatch bdiff".split():
98 if m in "mpatch bdiff".split():
97 ui.warn(_("(did you forget to compile extensions?)\n"))
99 ui.warn(_("(did you forget to compile extensions?)\n"))
98 elif m in "zlib".split():
100 elif m in "zlib".split():
99 ui.warn(_("(is your Python install correct?)\n"))
101 ui.warn(_("(is your Python install correct?)\n"))
100 except IOError, inst:
102 except IOError, inst:
101 if hasattr(inst, "code"):
103 if hasattr(inst, "code"):
102 ui.warn(_("abort: %s\n") % inst)
104 ui.warn(_("abort: %s\n") % inst)
103 elif hasattr(inst, "reason"):
105 elif hasattr(inst, "reason"):
104 try: # usually it is in the form (errno, strerror)
106 try: # usually it is in the form (errno, strerror)
105 reason = inst.reason.args[1]
107 reason = inst.reason.args[1]
106 except: # it might be anything, for example a string
108 except: # it might be anything, for example a string
107 reason = inst.reason
109 reason = inst.reason
108 ui.warn(_("abort: error: %s\n") % reason)
110 ui.warn(_("abort: error: %s\n") % reason)
109 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
111 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
110 if ui.debugflag:
112 if ui.debugflag:
111 ui.warn(_("broken pipe\n"))
113 ui.warn(_("broken pipe\n"))
112 elif getattr(inst, "strerror", None):
114 elif getattr(inst, "strerror", None):
113 if getattr(inst, "filename", None):
115 if getattr(inst, "filename", None):
114 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
116 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
115 else:
117 else:
116 ui.warn(_("abort: %s\n") % inst.strerror)
118 ui.warn(_("abort: %s\n") % inst.strerror)
117 else:
119 else:
118 raise
120 raise
119 except OSError, inst:
121 except OSError, inst:
120 if getattr(inst, "filename", None):
122 if getattr(inst, "filename", None):
121 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
123 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
122 else:
124 else:
123 ui.warn(_("abort: %s\n") % inst.strerror)
125 ui.warn(_("abort: %s\n") % inst.strerror)
124 except KeyboardInterrupt:
126 except KeyboardInterrupt:
125 try:
127 try:
126 ui.warn(_("interrupted!\n"))
128 ui.warn(_("interrupted!\n"))
127 except IOError, inst:
129 except IOError, inst:
128 if inst.errno == errno.EPIPE:
130 if inst.errno == errno.EPIPE:
129 if ui.debugflag:
131 if ui.debugflag:
130 ui.warn(_("\nbroken pipe\n"))
132 ui.warn(_("\nbroken pipe\n"))
131 else:
133 else:
132 raise
134 raise
133 except MemoryError:
135 except MemoryError:
134 ui.warn(_("abort: out of memory\n"))
136 ui.warn(_("abort: out of memory\n"))
135 except SystemExit, inst:
137 except SystemExit, inst:
136 # Commands shouldn't sys.exit directly, but give a return code.
138 # Commands shouldn't sys.exit directly, but give a return code.
137 # 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.
138 return inst.code
140 return inst.code
139 except socket.error, inst:
141 except socket.error, inst:
140 ui.warn(_("abort: %s\n") % inst.args[-1])
142 ui.warn(_("abort: %s\n") % inst.args[-1])
141 except:
143 except:
142 ui.warn(_("** unknown exception encountered, details follow\n"))
144 ui.warn(_("** unknown exception encountered, details follow\n"))
143 ui.warn(_("** report bug details to "
145 ui.warn(_("** report bug details to "
144 "http://www.selenic.com/mercurial/bts\n"))
146 "http://www.selenic.com/mercurial/bts\n"))
145 ui.warn(_("** or mercurial@selenic.com\n"))
147 ui.warn(_("** or mercurial@selenic.com\n"))
146 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
148 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
147 % util.version())
149 % util.version())
148 ui.warn(_("** Extensions loaded: %s\n")
150 ui.warn(_("** Extensions loaded: %s\n")
149 % ", ".join([x[0] for x in extensions.extensions()]))
151 % ", ".join([x[0] for x in extensions.extensions()]))
150 raise
152 raise
151
153
152 return -1
154 return -1
153
155
154 def _findrepo(p):
156 def _findrepo(p):
155 while not os.path.isdir(os.path.join(p, ".hg")):
157 while not os.path.isdir(os.path.join(p, ".hg")):
156 oldp, p = p, os.path.dirname(p)
158 oldp, p = p, os.path.dirname(p)
157 if p == oldp:
159 if p == oldp:
158 return None
160 return None
159
161
160 return p
162 return p
161
163
162 def _parse(ui, args):
164 def _parse(ui, args):
163 options = {}
165 options = {}
164 cmdoptions = {}
166 cmdoptions = {}
165
167
166 try:
168 try:
167 args = fancyopts.fancyopts(args, commands.globalopts, options)
169 args = fancyopts.fancyopts(args, commands.globalopts, options)
168 except fancyopts.getopt.GetoptError, inst:
170 except fancyopts.getopt.GetoptError, inst:
169 raise error.ParseError(None, inst)
171 raise error.ParseError(None, inst)
170
172
171 if args:
173 if args:
172 cmd, args = args[0], args[1:]
174 cmd, args = args[0], args[1:]
173 aliases, i = cmdutil.findcmd(cmd, commands.table,
175 aliases, i = cmdutil.findcmd(cmd, commands.table,
174 ui.config("ui", "strict"))
176 ui.config("ui", "strict"))
175 cmd = aliases[0]
177 cmd = aliases[0]
176 defaults = ui.config("defaults", cmd)
178 defaults = ui.config("defaults", cmd)
177 if defaults:
179 if defaults:
178 args = shlex.split(defaults) + args
180 args = shlex.split(defaults) + args
179 c = list(i[1])
181 c = list(i[1])
180 else:
182 else:
181 cmd = None
183 cmd = None
182 c = []
184 c = []
183
185
184 # combine global options into local
186 # combine global options into local
185 for o in commands.globalopts:
187 for o in commands.globalopts:
186 c.append((o[0], o[1], options[o[1]], o[3]))
188 c.append((o[0], o[1], options[o[1]], o[3]))
187
189
188 try:
190 try:
189 args = fancyopts.fancyopts(args, c, cmdoptions, True)
191 args = fancyopts.fancyopts(args, c, cmdoptions, True)
190 except fancyopts.getopt.GetoptError, inst:
192 except fancyopts.getopt.GetoptError, inst:
191 raise error.ParseError(cmd, inst)
193 raise error.ParseError(cmd, inst)
192
194
193 # separate global options back out
195 # separate global options back out
194 for o in commands.globalopts:
196 for o in commands.globalopts:
195 n = o[1]
197 n = o[1]
196 options[n] = cmdoptions[n]
198 options[n] = cmdoptions[n]
197 del cmdoptions[n]
199 del cmdoptions[n]
198
200
199 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
201 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
200
202
201 def _parseconfig(ui, config):
203 def _parseconfig(ui, config):
202 """parse the --config options from the command line"""
204 """parse the --config options from the command line"""
203 for cfg in config:
205 for cfg in config:
204 try:
206 try:
205 name, value = cfg.split('=', 1)
207 name, value = cfg.split('=', 1)
206 section, name = name.split('.', 1)
208 section, name = name.split('.', 1)
207 if not section or not name:
209 if not section or not name:
208 raise IndexError
210 raise IndexError
209 ui.setconfig(section, name, value)
211 ui.setconfig(section, name, value)
210 except (IndexError, ValueError):
212 except (IndexError, ValueError):
211 raise util.Abort(_('malformed --config option: %s') % cfg)
213 raise util.Abort(_('malformed --config option: %s') % cfg)
212
214
213 def _earlygetopt(aliases, args):
215 def _earlygetopt(aliases, args):
214 """Return list of values for an option (or aliases).
216 """Return list of values for an option (or aliases).
215
217
216 The values are listed in the order they appear in args.
218 The values are listed in the order they appear in args.
217 The options and values are removed from args.
219 The options and values are removed from args.
218 """
220 """
219 try:
221 try:
220 argcount = args.index("--")
222 argcount = args.index("--")
221 except ValueError:
223 except ValueError:
222 argcount = len(args)
224 argcount = len(args)
223 shortopts = [opt for opt in aliases if len(opt) == 2]
225 shortopts = [opt for opt in aliases if len(opt) == 2]
224 values = []
226 values = []
225 pos = 0
227 pos = 0
226 while pos < argcount:
228 while pos < argcount:
227 if args[pos] in aliases:
229 if args[pos] in aliases:
228 if pos + 1 >= argcount:
230 if pos + 1 >= argcount:
229 # ignore and let getopt report an error if there is no value
231 # ignore and let getopt report an error if there is no value
230 break
232 break
231 del args[pos]
233 del args[pos]
232 values.append(args.pop(pos))
234 values.append(args.pop(pos))
233 argcount -= 2
235 argcount -= 2
234 elif args[pos][:2] in shortopts:
236 elif args[pos][:2] in shortopts:
235 # short option can have no following space, e.g. hg log -Rfoo
237 # short option can have no following space, e.g. hg log -Rfoo
236 values.append(args.pop(pos)[2:])
238 values.append(args.pop(pos)[2:])
237 argcount -= 1
239 argcount -= 1
238 else:
240 else:
239 pos += 1
241 pos += 1
240 return values
242 return values
241
243
242 def runcommand(lui, repo, cmd, fullargs, ui, options, d):
244 def runcommand(lui, repo, cmd, fullargs, ui, options, d):
243 # run pre-hook, and abort if it fails
245 # run pre-hook, and abort if it fails
244 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
246 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
245 if ret:
247 if ret:
246 return ret
248 return ret
247 ret = _runcommand(ui, options, cmd, d)
249 ret = _runcommand(ui, options, cmd, d)
248 # run post-hook, passing command result
250 # run post-hook, passing command result
249 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
251 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
250 result = ret)
252 result = ret)
251 return ret
253 return ret
252
254
253 _loaded = {}
255 _loaded = {}
254 def _dispatch(ui, args):
256 def _dispatch(ui, args):
255 # read --config before doing anything else
257 # read --config before doing anything else
256 # (e.g. to change trust settings for reading .hg/hgrc)
258 # (e.g. to change trust settings for reading .hg/hgrc)
257 _parseconfig(ui, _earlygetopt(['--config'], args))
259 _parseconfig(ui, _earlygetopt(['--config'], args))
258
260
259 # check for cwd
261 # check for cwd
260 cwd = _earlygetopt(['--cwd'], args)
262 cwd = _earlygetopt(['--cwd'], args)
261 if cwd:
263 if cwd:
262 os.chdir(cwd[-1])
264 os.chdir(cwd[-1])
263
265
264 # read the local repository .hgrc into a local ui object
266 # read the local repository .hgrc into a local ui object
265 path = _findrepo(os.getcwd()) or ""
267 path = _findrepo(os.getcwd()) or ""
266 if not path:
268 if not path:
267 lui = ui
269 lui = ui
268 if path:
270 if path:
269 try:
271 try:
270 lui = _ui.ui(parentui=ui)
272 lui = _ui.ui(parentui=ui)
271 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
273 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
272 except IOError:
274 except IOError:
273 pass
275 pass
274
276
275 # now we can expand paths, even ones in .hg/hgrc
277 # now we can expand paths, even ones in .hg/hgrc
276 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
278 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
277 if rpath:
279 if rpath:
278 path = lui.expandpath(rpath[-1])
280 path = lui.expandpath(rpath[-1])
279 lui = _ui.ui(parentui=ui)
281 lui = _ui.ui(parentui=ui)
280 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
282 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
281
283
282 extensions.loadall(lui)
284 extensions.loadall(lui)
283 for name, module in extensions.extensions():
285 for name, module in extensions.extensions():
284 if name in _loaded:
286 if name in _loaded:
285 continue
287 continue
286
288
287 # setup extensions
289 # setup extensions
288 # TODO this should be generalized to scheme, where extensions can
290 # TODO this should be generalized to scheme, where extensions can
289 # redepend on other extensions. then we should toposort them, and
291 # redepend on other extensions. then we should toposort them, and
290 # do initialization in correct order
292 # do initialization in correct order
291 extsetup = getattr(module, 'extsetup', None)
293 extsetup = getattr(module, 'extsetup', None)
292 if extsetup:
294 if extsetup:
293 extsetup()
295 extsetup()
294
296
295 cmdtable = getattr(module, 'cmdtable', {})
297 cmdtable = getattr(module, 'cmdtable', {})
296 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
298 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
297 if overrides:
299 if overrides:
298 ui.warn(_("extension '%s' overrides commands: %s\n")
300 ui.warn(_("extension '%s' overrides commands: %s\n")
299 % (name, " ".join(overrides)))
301 % (name, " ".join(overrides)))
300 commands.table.update(cmdtable)
302 commands.table.update(cmdtable)
301 _loaded[name] = 1
303 _loaded[name] = 1
302 # check for fallback encoding
304 # check for fallback encoding
303 fallback = lui.config('ui', 'fallbackencoding')
305 fallback = lui.config('ui', 'fallbackencoding')
304 if fallback:
306 if fallback:
305 encoding.fallbackencoding = fallback
307 encoding.fallbackencoding = fallback
306
308
307 fullargs = args
309 fullargs = args
308 cmd, func, args, options, cmdoptions = _parse(lui, args)
310 cmd, func, args, options, cmdoptions = _parse(lui, args)
309
311
310 if options["config"]:
312 if options["config"]:
311 raise util.Abort(_("Option --config may not be abbreviated!"))
313 raise util.Abort(_("Option --config may not be abbreviated!"))
312 if options["cwd"]:
314 if options["cwd"]:
313 raise util.Abort(_("Option --cwd may not be abbreviated!"))
315 raise util.Abort(_("Option --cwd may not be abbreviated!"))
314 if options["repository"]:
316 if options["repository"]:
315 raise util.Abort(_(
317 raise util.Abort(_(
316 "Option -R has to be separated from other options (i.e. not -qR) "
318 "Option -R has to be separated from other options (i.e. not -qR) "
317 "and --repository may only be abbreviated as --repo!"))
319 "and --repository may only be abbreviated as --repo!"))
318
320
319 if options["encoding"]:
321 if options["encoding"]:
320 encoding.encoding = options["encoding"]
322 encoding.encoding = options["encoding"]
321 if options["encodingmode"]:
323 if options["encodingmode"]:
322 encoding.encodingmode = options["encodingmode"]
324 encoding.encodingmode = options["encodingmode"]
323 if options["time"]:
325 if options["time"]:
324 def get_times():
326 def get_times():
325 t = os.times()
327 t = os.times()
326 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
328 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
327 t = (t[0], t[1], t[2], t[3], time.clock())
329 t = (t[0], t[1], t[2], t[3], time.clock())
328 return t
330 return t
329 s = get_times()
331 s = get_times()
330 def print_time():
332 def print_time():
331 t = get_times()
333 t = get_times()
332 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
334 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
333 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
335 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
334 atexit.register(print_time)
336 atexit.register(print_time)
335
337
336 if options['verbose'] or options['debug'] or options['quiet']:
338 if options['verbose'] or options['debug'] or options['quiet']:
337 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
339 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
338 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
340 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
339 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
341 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
340 if options['traceback']:
342 if options['traceback']:
341 ui.setconfig('ui', 'traceback', 'on')
343 ui.setconfig('ui', 'traceback', 'on')
342 if options['noninteractive']:
344 if options['noninteractive']:
343 ui.setconfig('ui', 'interactive', 'off')
345 ui.setconfig('ui', 'interactive', 'off')
344
346
345 if options['help']:
347 if options['help']:
346 return commands.help_(ui, cmd, options['version'])
348 return commands.help_(ui, cmd, options['version'])
347 elif options['version']:
349 elif options['version']:
348 return commands.version_(ui)
350 return commands.version_(ui)
349 elif not cmd:
351 elif not cmd:
350 return commands.help_(ui, 'shortlist')
352 return commands.help_(ui, 'shortlist')
351
353
352 repo = None
354 repo = None
353 if cmd not in commands.norepo.split():
355 if cmd not in commands.norepo.split():
354 try:
356 try:
355 repo = hg.repository(ui, path=path)
357 repo = hg.repository(ui, path=path)
356 ui = repo.ui
358 ui = repo.ui
357 if not repo.local():
359 if not repo.local():
358 raise util.Abort(_("repository '%s' is not local") % path)
360 raise util.Abort(_("repository '%s' is not local") % path)
359 ui.setconfig("bundle", "mainreporoot", repo.root)
361 ui.setconfig("bundle", "mainreporoot", repo.root)
360 except error.RepoError:
362 except error.RepoError:
361 if cmd not in commands.optionalrepo.split():
363 if cmd not in commands.optionalrepo.split():
362 if args and not path: # try to infer -R from command args
364 if args and not path: # try to infer -R from command args
363 repos = map(_findrepo, args)
365 repos = map(_findrepo, args)
364 guess = repos[0]
366 guess = repos[0]
365 if guess and repos.count(guess) == len(repos):
367 if guess and repos.count(guess) == len(repos):
366 return _dispatch(ui, ['--repository', guess] + fullargs)
368 return _dispatch(ui, ['--repository', guess] + fullargs)
367 if not path:
369 if not path:
368 raise error.RepoError(_("There is no Mercurial repository"
370 raise error.RepoError(_("There is no Mercurial repository"
369 " here (.hg not found)"))
371 " here (.hg not found)"))
370 raise
372 raise
371 args.insert(0, repo)
373 args.insert(0, repo)
372 elif rpath:
374 elif rpath:
373 ui.warn("warning: --repository ignored\n")
375 ui.warn("warning: --repository ignored\n")
374
376
375 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
377 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
376 return runcommand(lui, repo, cmd, fullargs, ui, options, d)
378 return runcommand(lui, repo, cmd, fullargs, ui, options, d)
377
379
378 def _runcommand(ui, options, cmd, cmdfunc):
380 def _runcommand(ui, options, cmd, cmdfunc):
379 def checkargs():
381 def checkargs():
380 try:
382 try:
381 return cmdfunc()
383 return cmdfunc()
382 except error.SignatureError:
384 except error.SignatureError:
383 raise error.ParseError(cmd, _("invalid arguments"))
385 raise error.ParseError(cmd, _("invalid arguments"))
384
386
385 if options['profile']:
387 if options['profile']:
386 format = ui.config('profiling', 'format', default='text')
388 format = ui.config('profiling', 'format', default='text')
387
389
388 if not format in ['text', 'kcachegrind']:
390 if not format in ['text', 'kcachegrind']:
389 ui.warn(_("unrecognized profiling format '%s'"
391 ui.warn(_("unrecognized profiling format '%s'"
390 " - Ignored\n") % format)
392 " - Ignored\n") % format)
391 format = 'text'
393 format = 'text'
392
394
393 output = ui.config('profiling', 'output')
395 output = ui.config('profiling', 'output')
394
396
395 if output:
397 if output:
396 path = os.path.expanduser(output)
398 path = os.path.expanduser(output)
397 path = ui.expandpath(path)
399 path = ui.expandpath(path)
398 ostream = open(path, 'wb')
400 ostream = open(path, 'wb')
399 else:
401 else:
400 ostream = sys.stderr
402 ostream = sys.stderr
401
403
402 try:
404 try:
403 from mercurial import lsprof
405 from mercurial import lsprof
404 except ImportError:
406 except ImportError:
405 raise util.Abort(_(
407 raise util.Abort(_(
406 'lsprof not available - install from '
408 'lsprof not available - install from '
407 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
409 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
408 p = lsprof.Profiler()
410 p = lsprof.Profiler()
409 p.enable(subcalls=True)
411 p.enable(subcalls=True)
410 try:
412 try:
411 return checkargs()
413 return checkargs()
412 finally:
414 finally:
413 p.disable()
415 p.disable()
414
416
415 if format == 'kcachegrind':
417 if format == 'kcachegrind':
416 import lsprofcalltree
418 import lsprofcalltree
417 calltree = lsprofcalltree.KCacheGrind(p)
419 calltree = lsprofcalltree.KCacheGrind(p)
418 calltree.output(ostream)
420 calltree.output(ostream)
419 else:
421 else:
420 # format == 'text'
422 # format == 'text'
421 stats = lsprof.Stats(p.getstats())
423 stats = lsprof.Stats(p.getstats())
422 stats.sort()
424 stats.sort()
423 stats.pprint(top=10, file=ostream, climit=5)
425 stats.pprint(top=10, file=ostream, climit=5)
424
426
425 if output:
427 if output:
426 ostream.close()
428 ostream.close()
427 else:
429 else:
428 return checkargs()
430 return checkargs()
@@ -1,67 +1,70 b''
1 """
1 """
2 error.py - Mercurial exceptions
2 error.py - Mercurial exceptions
3
3
4 This allows us to catch exceptions at higher levels without forcing imports
4 This allows us to catch exceptions at higher levels without forcing imports
5
5
6 Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
6 Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
7
7
8 This software may be used and distributed according to the terms
8 This software may be used and distributed according to the terms
9 of the GNU General Public License, incorporated herein by reference.
9 of the GNU General Public License, incorporated herein by reference.
10 """
10 """
11
11
12 # Do not import anything here, please
12 # Do not import anything here, please
13
13
14 class RevlogError(Exception):
14 class RevlogError(Exception):
15 pass
15 pass
16
16
17 class LookupError(RevlogError, KeyError):
17 class LookupError(RevlogError, KeyError):
18 def __init__(self, name, index, message):
18 def __init__(self, name, index, message):
19 self.name = name
19 self.name = name
20 if isinstance(name, str) and len(name) == 20:
20 if isinstance(name, str) and len(name) == 20:
21 from node import short
21 from node import short
22 name = short(name)
22 name = short(name)
23 RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
23 RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
24
24
25 def __str__(self):
25 def __str__(self):
26 return RevlogError.__str__(self)
26 return RevlogError.__str__(self)
27
27
28 class ParseError(Exception):
28 class ParseError(Exception):
29 """Exception raised on errors in parsing the command line."""
29 """Exception raised on errors in parsing the command line."""
30
30
31 class ConfigError(Exception):
32 'Exception raised when parsing config files'
33
31 class RepoError(Exception):
34 class RepoError(Exception):
32 pass
35 pass
33
36
34 class CapabilityError(RepoError):
37 class CapabilityError(RepoError):
35 pass
38 pass
36
39
37 class LockError(IOError):
40 class LockError(IOError):
38 def __init__(self, errno, strerror, filename, desc):
41 def __init__(self, errno, strerror, filename, desc):
39 IOError.__init__(self, errno, strerror, filename)
42 IOError.__init__(self, errno, strerror, filename)
40 self.desc = desc
43 self.desc = desc
41
44
42 class LockHeld(LockError):
45 class LockHeld(LockError):
43 def __init__(self, errno, filename, desc, locker):
46 def __init__(self, errno, filename, desc, locker):
44 LockError.__init__(self, errno, 'Lock held', filename, desc)
47 LockError.__init__(self, errno, 'Lock held', filename, desc)
45 self.locker = locker
48 self.locker = locker
46
49
47 class LockUnavailable(LockError):
50 class LockUnavailable(LockError):
48 pass
51 pass
49
52
50 class ResponseError(Exception):
53 class ResponseError(Exception):
51 """Raised to print an error with part of output and exit."""
54 """Raised to print an error with part of output and exit."""
52
55
53 class UnknownCommand(Exception):
56 class UnknownCommand(Exception):
54 """Exception raised if command is not in the command table."""
57 """Exception raised if command is not in the command table."""
55
58
56 class AmbiguousCommand(Exception):
59 class AmbiguousCommand(Exception):
57 """Exception raised if command shortcut matches more than one command."""
60 """Exception raised if command shortcut matches more than one command."""
58
61
59 # derived from KeyboardInterrupt to simplify some breakout code
62 # derived from KeyboardInterrupt to simplify some breakout code
60 class SignalInterrupt(KeyboardInterrupt):
63 class SignalInterrupt(KeyboardInterrupt):
61 """Exception raised on SIGTERM and SIGHUP."""
64 """Exception raised on SIGTERM and SIGHUP."""
62
65
63 class SignatureError(Exception):
66 class SignatureError(Exception):
64 pass
67 pass
65
68
66 class Abort(Exception):
69 class Abort(Exception):
67 """Raised if a command needs to print an error and exit."""
70 """Raised if a command needs to print an error and exit."""
@@ -1,401 +1,358 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, re, socket, sys, tempfile
9 import errno, getpass, os, re, socket, sys, tempfile
10 import ConfigParser, traceback, util
10 import config, traceback, util, error
11
11
12 def updateconfig(source, dest, sections=None):
12 _booleans = {'1':True, 'yes':True, 'true':True, 'on':True,
13 if not sections:
13 '0':False, 'no':False, 'false':False, 'off':False}
14 sections = source.sections()
15 for section in sections:
16 if not dest.has_section(section):
17 dest.add_section(section)
18 if not source.has_section(section):
19 continue
20 for name, value in source.items(section, raw=True):
21 dest.set(section, name, value)
22
14
23 class ui(object):
15 class ui(object):
24 def __init__(self, parentui=None):
16 def __init__(self, parentui=None):
25 self.buffers = []
17 self.buffers = []
26 self.quiet = self.verbose = self.debugflag = self.traceback = False
18 self.quiet = self.verbose = self.debugflag = self.traceback = False
27 self.interactive = self.report_untrusted = True
19 self.interactive = self.report_untrusted = True
28 self.overlay = util.configparser()
20 self.overlay = config.config()
29 self.cdata = util.configparser()
21 self.cdata = config.config()
30 self.ucdata = util.configparser()
22 self.ucdata = config.config()
31 self.parentui = None
23 self.parentui = None
32 self.trusted_users = {}
24 self.trusted_users = {}
33 self.trusted_groups = {}
25 self.trusted_groups = {}
34
26
35 if parentui:
27 if parentui:
36 # parentui may point to an ui object which is already a child
28 # parentui may point to an ui object which is already a child
37 self.parentui = parentui.parentui or parentui
29 self.parentui = parentui.parentui or parentui
38 updateconfig(self.parentui.cdata, self.cdata)
30 self.cdata.update(self.parentui.cdata)
39 updateconfig(self.parentui.ucdata, self.ucdata)
31 self.ucdata.update(self.parentui.ucdata)
40 # we want the overlay from the parent, not the root
32 # we want the overlay from the parent, not the root
41 updateconfig(parentui.overlay, self.overlay)
33 self.overlay.update(parentui.overlay)
42 self.buffers = parentui.buffers
34 self.buffers = parentui.buffers
43 self.trusted_users = parentui.trusted_users.copy()
35 self.trusted_users = parentui.trusted_users.copy()
44 self.trusted_groups = parentui.trusted_groups.copy()
36 self.trusted_groups = parentui.trusted_groups.copy()
45 self.fixconfig()
37 self.fixconfig()
46 else:
38 else:
47 # we always trust global config files
39 # we always trust global config files
48 for f in util.rcpath():
40 for f in util.rcpath():
49 self.readconfig(f, assumetrusted=True)
41 self.readconfig(f, assumetrusted=True)
50
42
51 def __getattr__(self, key):
43 def __getattr__(self, key):
52 return getattr(self.parentui, key)
44 return getattr(self.parentui, key)
53
45
54 _isatty = None
46 _isatty = None
55 def isatty(self):
47 def isatty(self):
56 if ui._isatty is None:
48 if ui._isatty is None:
57 try:
49 try:
58 ui._isatty = sys.stdin.isatty()
50 ui._isatty = sys.stdin.isatty()
59 except AttributeError: # not a real file object
51 except AttributeError: # not a real file object
60 ui._isatty = False
52 ui._isatty = False
61 return ui._isatty
53 return ui._isatty
62
54
63 def _is_trusted(self, fp, f):
55 def _is_trusted(self, fp, f):
64 st = util.fstat(fp)
56 st = util.fstat(fp)
65 if util.isowner(fp, st):
57 if util.isowner(fp, st):
66 return True
58 return True
67
59
68 tusers = self.trusted_users
60 tusers = self.trusted_users
69 tgroups = self.trusted_groups
61 tgroups = self.trusted_groups
70 if '*' in tusers or '*' in tgroups:
62 if '*' in tusers or '*' in tgroups:
71 return True
63 return True
72
64
73 user = util.username(st.st_uid)
65 user = util.username(st.st_uid)
74 group = util.groupname(st.st_gid)
66 group = util.groupname(st.st_gid)
75 if user in tusers or group in tgroups or user == util.username():
67 if user in tusers or group in tgroups or user == util.username():
76 return True
68 return True
77
69
78 if self.report_untrusted:
70 if self.report_untrusted:
79 self.warn(_('Not trusting file %s from untrusted '
71 self.warn(_('Not trusting file %s from untrusted '
80 'user %s, group %s\n') % (f, user, group))
72 'user %s, group %s\n') % (f, user, group))
81 return False
73 return False
82
74
83 def readconfig(self, filename, root=None, assumetrusted=False,
75 def readconfig(self, filename, root=None, assumetrusted=False,
84 sections = None):
76 sections = None):
85 try:
77 try:
86 fp = open(filename)
78 fp = open(filename)
87 except IOError:
79 except IOError:
88 if not sections: # ignore unless we were looking for something
80 if not sections: # ignore unless we were looking for something
89 return
81 return
90 raise
82 raise
91
83
92 cdata = util.configparser()
84 cdata = config.config()
93 trusted = sections or assumetrusted or self._is_trusted(fp, filename)
85 trusted = sections or assumetrusted or self._is_trusted(fp, filename)
94
86
95 try:
87 try:
96 cdata.readfp(fp, filename)
88 cdata.read(filename, fp)
97 except ConfigParser.ParsingError, inst:
89 except error.ConfigError, inst:
98 msg = _("Failed to parse %s\n%s") % (filename, inst)
99 if trusted:
90 if trusted:
100 raise util.Abort(msg)
91 raise
101 self.warn(_("Ignored: %s\n") % msg)
92 self.warn(_("Ignored: %s\n") % str(inst))
102
93
103 if trusted:
94 if trusted:
104 updateconfig(cdata, self.cdata, sections)
95 self.cdata.update(cdata, sections)
105 updateconfig(self.overlay, self.cdata, sections)
96 self.cdata.update(self.overlay, sections)
106 updateconfig(cdata, self.ucdata, sections)
97 self.ucdata.update(cdata, sections)
107 updateconfig(self.overlay, self.ucdata, sections)
98 self.ucdata.update(self.overlay, sections)
108
99
109 if root is None:
100 if root is None:
110 root = os.path.expanduser('~')
101 root = os.path.expanduser('~')
111 self.fixconfig(root=root)
102 self.fixconfig(root=root)
112
103
113 def fixconfig(self, section=None, name=None, value=None, root=None):
104 def fixconfig(self, section=None, name=None, value=None, root=None):
114 # translate paths relative to root (or home) into absolute paths
105 # translate paths relative to root (or home) into absolute paths
115 if section is None or section == 'paths':
106 if section is None or section == 'paths':
116 if root is None:
107 if root is None:
117 root = os.getcwd()
108 root = os.getcwd()
118 items = section and [(name, value)] or []
109 items = section and [(name, value)] or []
119 for cdata in self.cdata, self.ucdata, self.overlay:
110 for cdata in self.cdata, self.ucdata, self.overlay:
120 if not items and cdata.has_section('paths'):
111 if not items and 'paths' in cdata:
121 pathsitems = cdata.items('paths')
112 pathsitems = cdata.items('paths')
122 else:
113 else:
123 pathsitems = items
114 pathsitems = items
124 for n, path in pathsitems:
115 for n, path in pathsitems:
125 if path and "://" not in path and not os.path.isabs(path):
116 if path and "://" not in path and not os.path.isabs(path):
126 cdata.set("paths", n,
117 cdata.set("paths", n,
127 os.path.normpath(os.path.join(root, path)))
118 os.path.normpath(os.path.join(root, path)))
128
119
129 # update ui options
120 # update ui options
130 if section is None or section == 'ui':
121 if section is None or section == 'ui':
131 self.debugflag = self.configbool('ui', 'debug')
122 self.debugflag = self.configbool('ui', 'debug')
132 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
123 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
133 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
124 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
134 if self.verbose and self.quiet:
125 if self.verbose and self.quiet:
135 self.quiet = self.verbose = False
126 self.quiet = self.verbose = False
136
127
137 self.report_untrusted = self.configbool("ui", "report_untrusted",
128 self.report_untrusted = self.configbool("ui", "report_untrusted",
138 True)
129 True)
139 self.interactive = self.configbool("ui", "interactive",
130 self.interactive = self.configbool("ui", "interactive",
140 self.isatty())
131 self.isatty())
141 self.traceback = self.configbool('ui', 'traceback', False)
132 self.traceback = self.configbool('ui', 'traceback', False)
142
133
143 # update trust information
134 # update trust information
144 if section is None or section == 'trusted':
135 if section is None or section == 'trusted':
145 for user in self.configlist('trusted', 'users'):
136 for user in self.configlist('trusted', 'users'):
146 self.trusted_users[user] = 1
137 self.trusted_users[user] = 1
147 for group in self.configlist('trusted', 'groups'):
138 for group in self.configlist('trusted', 'groups'):
148 self.trusted_groups[group] = 1
139 self.trusted_groups[group] = 1
149
140
150 def setconfig(self, section, name, value):
141 def setconfig(self, section, name, value):
151 for cdata in (self.overlay, self.cdata, self.ucdata):
142 for cdata in (self.overlay, self.cdata, self.ucdata):
152 if not cdata.has_section(section):
153 cdata.add_section(section)
154 cdata.set(section, name, value)
143 cdata.set(section, name, value)
155 self.fixconfig(section, name, value)
144 self.fixconfig(section, name, value)
156
145
157 def _get_cdata(self, untrusted):
146 def _get_cdata(self, untrusted):
158 if untrusted:
147 if untrusted:
159 return self.ucdata
148 return self.ucdata
160 return self.cdata
149 return self.cdata
161
150
162 def _config(self, section, name, default, funcname, untrusted, abort):
151 def config(self, section, name, default=None, untrusted=False):
163 cdata = self._get_cdata(untrusted)
152 value = self._get_cdata(untrusted).get(section, name, default)
164 if cdata.has_option(section, name):
165 try:
166 func = getattr(cdata, funcname)
167 return func(section, name)
168 except (ConfigParser.InterpolationError, ValueError), inst:
169 msg = _("Error in configuration section [%s] "
170 "parameter '%s':\n%s") % (section, name, inst)
171 if abort:
172 raise util.Abort(msg)
173 self.warn(_("Ignored: %s\n") % msg)
174 return default
175
176 def _configcommon(self, section, name, default, funcname, untrusted):
177 value = self._config(section, name, default, funcname,
178 untrusted, abort=True)
179 if self.debugflag and not untrusted:
153 if self.debugflag and not untrusted:
180 uvalue = self._config(section, name, None, funcname,
154 uvalue = self.ucdata.get(section, name)
181 untrusted=True, abort=False)
182 if uvalue is not None and uvalue != value:
155 if uvalue is not None and uvalue != value:
183 self.warn(_("Ignoring untrusted configuration option "
156 self.warn(_("Ignoring untrusted configuration option "
184 "%s.%s = %s\n") % (section, name, uvalue))
157 "%s.%s = %s\n") % (section, name, uvalue))
185 return value
158 return value
186
159
187 def config(self, section, name, default=None, untrusted=False):
188 return self._configcommon(section, name, default, 'get', untrusted)
189
190 def configbool(self, section, name, default=False, untrusted=False):
160 def configbool(self, section, name, default=False, untrusted=False):
191 return self._configcommon(section, name, default, 'getboolean',
161 v = self.config(section, name, None, untrusted)
192 untrusted)
162 if v == None:
163 return default
164 if v.lower() not in _booleans:
165 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
166 % (section, name, v))
167 return _booleans[v.lower()]
193
168
194 def configlist(self, section, name, default=None, untrusted=False):
169 def configlist(self, section, name, default=None, untrusted=False):
195 """Return a list of comma/space separated strings"""
170 """Return a list of comma/space separated strings"""
196 result = self.config(section, name, untrusted=untrusted)
171 result = self.config(section, name, untrusted=untrusted)
197 if result is None:
172 if result is None:
198 result = default or []
173 result = default or []
199 if isinstance(result, basestring):
174 if isinstance(result, basestring):
200 result = result.replace(",", " ").split()
175 result = result.replace(",", " ").split()
201 return result
176 return result
202
177
203 def has_section(self, section, untrusted=False):
178 def has_section(self, section, untrusted=False):
204 '''tell whether section exists in config.'''
179 '''tell whether section exists in config.'''
205 cdata = self._get_cdata(untrusted)
180 return section in self._get_cdata(untrusted)
206 return cdata.has_section(section)
207
208 def _configitems(self, section, untrusted, abort):
209 items = {}
210 cdata = self._get_cdata(untrusted)
211 if cdata.has_section(section):
212 try:
213 items.update(dict(cdata.items(section)))
214 except ConfigParser.InterpolationError, inst:
215 msg = _("Error in configuration section [%s]:\n"
216 "%s") % (section, inst)
217 if abort:
218 raise util.Abort(msg)
219 self.warn(_("Ignored: %s\n") % msg)
220 return items
221
181
222 def configitems(self, section, untrusted=False):
182 def configitems(self, section, untrusted=False):
223 items = self._configitems(section, untrusted=untrusted, abort=True)
183 items = self._get_cdata(untrusted).items(section)
224 if self.debugflag and not untrusted:
184 if self.debugflag and not untrusted:
225 uitems = self._configitems(section, untrusted=True, abort=False)
185 for k,v in self.ucdata.items(section):
226 for k in util.sort(uitems):
186 if self.cdata.get(section, k) != v:
227 if uitems[k] != items.get(k):
228 self.warn(_("Ignoring untrusted configuration option "
187 self.warn(_("Ignoring untrusted configuration option "
229 "%s.%s = %s\n") % (section, k, uitems[k]))
188 "%s.%s = %s\n") % (section, k, v))
230 return util.sort(items.items())
189 return items
231
190
232 def walkconfig(self, untrusted=False):
191 def walkconfig(self, untrusted=False):
233 cdata = self._get_cdata(untrusted)
192 cdata = self._get_cdata(untrusted)
234 sections = cdata.sections()
193 for section in cdata.sections():
235 sections.sort()
236 for section in sections:
237 for name, value in self.configitems(section, untrusted):
194 for name, value in self.configitems(section, untrusted):
238 yield section, name, str(value).replace('\n', '\\n')
195 yield section, name, str(value).replace('\n', '\\n')
239
196
240 def username(self):
197 def username(self):
241 """Return default username to be used in commits.
198 """Return default username to be used in commits.
242
199
243 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
200 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
244 and stop searching if one of these is set.
201 and stop searching if one of these is set.
245 If not found and ui.askusername is True, ask the user, else use
202 If not found and ui.askusername is True, ask the user, else use
246 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
203 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
247 """
204 """
248 user = os.environ.get("HGUSER")
205 user = os.environ.get("HGUSER")
249 if user is None:
206 if user is None:
250 user = self.config("ui", "username")
207 user = self.config("ui", "username")
251 if user is None:
208 if user is None:
252 user = os.environ.get("EMAIL")
209 user = os.environ.get("EMAIL")
253 if user is None and self.configbool("ui", "askusername"):
210 if user is None and self.configbool("ui", "askusername"):
254 user = self.prompt(_("enter a commit username:"), default=None)
211 user = self.prompt(_("enter a commit username:"), default=None)
255 if user is None:
212 if user is None:
256 try:
213 try:
257 user = '%s@%s' % (util.getuser(), socket.getfqdn())
214 user = '%s@%s' % (util.getuser(), socket.getfqdn())
258 self.warn(_("No username found, using '%s' instead\n") % user)
215 self.warn(_("No username found, using '%s' instead\n") % user)
259 except KeyError:
216 except KeyError:
260 pass
217 pass
261 if not user:
218 if not user:
262 raise util.Abort(_("Please specify a username."))
219 raise util.Abort(_("Please specify a username."))
263 if "\n" in user:
220 if "\n" in user:
264 raise util.Abort(_("username %s contains a newline\n") % repr(user))
221 raise util.Abort(_("username %s contains a newline\n") % repr(user))
265 return user
222 return user
266
223
267 def shortuser(self, user):
224 def shortuser(self, user):
268 """Return a short representation of a user name or email address."""
225 """Return a short representation of a user name or email address."""
269 if not self.verbose: user = util.shortuser(user)
226 if not self.verbose: user = util.shortuser(user)
270 return user
227 return user
271
228
272 def expandpath(self, loc, default=None):
229 def expandpath(self, loc, default=None):
273 """Return repository location relative to cwd or from [paths]"""
230 """Return repository location relative to cwd or from [paths]"""
274 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
231 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
275 return loc
232 return loc
276
233
277 path = self.config("paths", loc)
234 path = self.config("paths", loc)
278 if not path and default is not None:
235 if not path and default is not None:
279 path = self.config("paths", default)
236 path = self.config("paths", default)
280 return path or loc
237 return path or loc
281
238
282 def pushbuffer(self):
239 def pushbuffer(self):
283 self.buffers.append([])
240 self.buffers.append([])
284
241
285 def popbuffer(self):
242 def popbuffer(self):
286 return "".join(self.buffers.pop())
243 return "".join(self.buffers.pop())
287
244
288 def write(self, *args):
245 def write(self, *args):
289 if self.buffers:
246 if self.buffers:
290 self.buffers[-1].extend([str(a) for a in args])
247 self.buffers[-1].extend([str(a) for a in args])
291 else:
248 else:
292 for a in args:
249 for a in args:
293 sys.stdout.write(str(a))
250 sys.stdout.write(str(a))
294
251
295 def write_err(self, *args):
252 def write_err(self, *args):
296 try:
253 try:
297 if not sys.stdout.closed: sys.stdout.flush()
254 if not sys.stdout.closed: sys.stdout.flush()
298 for a in args:
255 for a in args:
299 sys.stderr.write(str(a))
256 sys.stderr.write(str(a))
300 # stderr may be buffered under win32 when redirected to files,
257 # stderr may be buffered under win32 when redirected to files,
301 # including stdout.
258 # including stdout.
302 if not sys.stderr.closed: sys.stderr.flush()
259 if not sys.stderr.closed: sys.stderr.flush()
303 except IOError, inst:
260 except IOError, inst:
304 if inst.errno != errno.EPIPE:
261 if inst.errno != errno.EPIPE:
305 raise
262 raise
306
263
307 def flush(self):
264 def flush(self):
308 try: sys.stdout.flush()
265 try: sys.stdout.flush()
309 except: pass
266 except: pass
310 try: sys.stderr.flush()
267 try: sys.stderr.flush()
311 except: pass
268 except: pass
312
269
313 def _readline(self, prompt=''):
270 def _readline(self, prompt=''):
314 if self.isatty():
271 if self.isatty():
315 try:
272 try:
316 # magically add command line editing support, where
273 # magically add command line editing support, where
317 # available
274 # available
318 import readline
275 import readline
319 # force demandimport to really load the module
276 # force demandimport to really load the module
320 readline.read_history_file
277 readline.read_history_file
321 # windows sometimes raises something other than ImportError
278 # windows sometimes raises something other than ImportError
322 except Exception:
279 except Exception:
323 pass
280 pass
324 line = raw_input(prompt)
281 line = raw_input(prompt)
325 # When stdin is in binary mode on Windows, it can cause
282 # When stdin is in binary mode on Windows, it can cause
326 # raw_input() to emit an extra trailing carriage return
283 # raw_input() to emit an extra trailing carriage return
327 if os.linesep == '\r\n' and line and line[-1] == '\r':
284 if os.linesep == '\r\n' and line and line[-1] == '\r':
328 line = line[:-1]
285 line = line[:-1]
329 return line
286 return line
330
287
331 def prompt(self, msg, pat=None, default="y"):
288 def prompt(self, msg, pat=None, default="y"):
332 """Prompt user with msg, read response, and ensure it matches pat
289 """Prompt user with msg, read response, and ensure it matches pat
333
290
334 If not interactive -- the default is returned
291 If not interactive -- the default is returned
335 """
292 """
336 if not self.interactive:
293 if not self.interactive:
337 self.note(msg, ' ', default, "\n")
294 self.note(msg, ' ', default, "\n")
338 return default
295 return default
339 while True:
296 while True:
340 try:
297 try:
341 r = self._readline(msg + ' ')
298 r = self._readline(msg + ' ')
342 if not r:
299 if not r:
343 return default
300 return default
344 if not pat or re.match(pat, r):
301 if not pat or re.match(pat, r):
345 return r
302 return r
346 else:
303 else:
347 self.write(_("unrecognized response\n"))
304 self.write(_("unrecognized response\n"))
348 except EOFError:
305 except EOFError:
349 raise util.Abort(_('response expected'))
306 raise util.Abort(_('response expected'))
350
307
351 def getpass(self, prompt=None, default=None):
308 def getpass(self, prompt=None, default=None):
352 if not self.interactive: return default
309 if not self.interactive: return default
353 try:
310 try:
354 return getpass.getpass(prompt or _('password: '))
311 return getpass.getpass(prompt or _('password: '))
355 except EOFError:
312 except EOFError:
356 raise util.Abort(_('response expected'))
313 raise util.Abort(_('response expected'))
357 def status(self, *msg):
314 def status(self, *msg):
358 if not self.quiet: self.write(*msg)
315 if not self.quiet: self.write(*msg)
359 def warn(self, *msg):
316 def warn(self, *msg):
360 self.write_err(*msg)
317 self.write_err(*msg)
361 def note(self, *msg):
318 def note(self, *msg):
362 if self.verbose: self.write(*msg)
319 if self.verbose: self.write(*msg)
363 def debug(self, *msg):
320 def debug(self, *msg):
364 if self.debugflag: self.write(*msg)
321 if self.debugflag: self.write(*msg)
365 def edit(self, text, user):
322 def edit(self, text, user):
366 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
323 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
367 text=True)
324 text=True)
368 try:
325 try:
369 f = os.fdopen(fd, "w")
326 f = os.fdopen(fd, "w")
370 f.write(text)
327 f.write(text)
371 f.close()
328 f.close()
372
329
373 editor = self.geteditor()
330 editor = self.geteditor()
374
331
375 util.system("%s \"%s\"" % (editor, name),
332 util.system("%s \"%s\"" % (editor, name),
376 environ={'HGUSER': user},
333 environ={'HGUSER': user},
377 onerr=util.Abort, errprefix=_("edit failed"))
334 onerr=util.Abort, errprefix=_("edit failed"))
378
335
379 f = open(name)
336 f = open(name)
380 t = f.read()
337 t = f.read()
381 f.close()
338 f.close()
382 t = re.sub("(?m)^HG:.*\n", "", t)
339 t = re.sub("(?m)^HG:.*\n", "", t)
383 finally:
340 finally:
384 os.unlink(name)
341 os.unlink(name)
385
342
386 return t
343 return t
387
344
388 def print_exc(self):
345 def print_exc(self):
389 '''print exception traceback if traceback printing enabled.
346 '''print exception traceback if traceback printing enabled.
390 only to call in exception handler. returns true if traceback
347 only to call in exception handler. returns true if traceback
391 printed.'''
348 printed.'''
392 if self.traceback:
349 if self.traceback:
393 traceback.print_exc()
350 traceback.print_exc()
394 return self.traceback
351 return self.traceback
395
352
396 def geteditor(self):
353 def geteditor(self):
397 '''return editor to use'''
354 '''return editor to use'''
398 return (os.environ.get("HGEDITOR") or
355 return (os.environ.get("HGEDITOR") or
399 self.config("ui", "editor") or
356 self.config("ui", "editor") or
400 os.environ.get("VISUAL") or
357 os.environ.get("VISUAL") or
401 os.environ.get("EDITOR", "vi"))
358 os.environ.get("EDITOR", "vi"))
@@ -1,16 +1,13 b''
1 abort: Failed to parse .../t/.hg/hgrc
1 hg: config error at .../t/.hg/hgrc:1: 'invalid'
2 File contains no section headers.
3 file: .../t/.hg/hgrc, line: 1
4 'invalid\n'
5 updating working directory
2 updating working directory
6 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
7 [paths]
4 [paths]
8 default = .../foo%%bar
5 default = .../foo%%bar
9 default = .../foo%bar
6 default = .../foo%%bar
10 bundle.mainreporoot=.../foobar
7 bundle.mainreporoot=.../foobar
11 defaults.backout=-d "0 0"
8 defaults.backout=-d "0 0"
12 defaults.commit=-d "0 0"
9 defaults.commit=-d "0 0"
13 defaults.debugrawcommit=-d "0 0"
10 defaults.debugrawcommit=-d "0 0"
14 defaults.tag=-d "0 0"
11 defaults.tag=-d "0 0"
15 paths.default=.../foo%bar
12 paths.default=.../foo%%bar
16 ui.slash=True
13 ui.slash=True
@@ -1,211 +1,190 b''
1 # Since it's not easy to write a test that portably deals
1 # Since it's not easy to write a test that portably deals
2 # with files from different users/groups, we cheat a bit by
2 # with files from different users/groups, we cheat a bit by
3 # monkey-patching some functions in the util module
3 # monkey-patching some functions in the util module
4
4
5 import os
5 import os
6 from mercurial import ui, util
6 from mercurial import ui, util, error
7
7
8 hgrc = os.environ['HGRCPATH']
8 hgrc = os.environ['HGRCPATH']
9 f = open(hgrc)
9 f = open(hgrc)
10 basehgrc = f.read()
10 basehgrc = f.read()
11 f.close()
11 f.close()
12
12
13 def testui(user='foo', group='bar', tusers=(), tgroups=(),
13 def testui(user='foo', group='bar', tusers=(), tgroups=(),
14 cuser='foo', cgroup='bar', debug=False, silent=False):
14 cuser='foo', cgroup='bar', debug=False, silent=False):
15 # user, group => owners of the file
15 # user, group => owners of the file
16 # tusers, tgroups => trusted users/groups
16 # tusers, tgroups => trusted users/groups
17 # cuser, cgroup => user/group of the current process
17 # cuser, cgroup => user/group of the current process
18
18
19 # write a global hgrc with the list of trusted users/groups and
19 # write a global hgrc with the list of trusted users/groups and
20 # some setting so that we can be sure it was read
20 # some setting so that we can be sure it was read
21 f = open(hgrc, 'w')
21 f = open(hgrc, 'w')
22 f.write(basehgrc)
22 f.write(basehgrc)
23 f.write('\n[paths]\n')
23 f.write('\n[paths]\n')
24 f.write('global = /some/path\n\n')
24 f.write('global = /some/path\n\n')
25
25
26 if tusers or tgroups:
26 if tusers or tgroups:
27 f.write('[trusted]\n')
27 f.write('[trusted]\n')
28 if tusers:
28 if tusers:
29 f.write('users = %s\n' % ', '.join(tusers))
29 f.write('users = %s\n' % ', '.join(tusers))
30 if tgroups:
30 if tgroups:
31 f.write('groups = %s\n' % ', '.join(tgroups))
31 f.write('groups = %s\n' % ', '.join(tgroups))
32 f.close()
32 f.close()
33
33
34 # override the functions that give names to uids and gids
34 # override the functions that give names to uids and gids
35 def username(uid=None):
35 def username(uid=None):
36 if uid is None:
36 if uid is None:
37 return cuser
37 return cuser
38 return user
38 return user
39 util.username = username
39 util.username = username
40
40
41 def groupname(gid=None):
41 def groupname(gid=None):
42 if gid is None:
42 if gid is None:
43 return 'bar'
43 return 'bar'
44 return group
44 return group
45 util.groupname = groupname
45 util.groupname = groupname
46
46
47 def isowner(fp, st=None):
47 def isowner(fp, st=None):
48 return user == cuser
48 return user == cuser
49 util.isowner = isowner
49 util.isowner = isowner
50
50
51 # try to read everything
51 # try to read everything
52 #print '# File belongs to user %s, group %s' % (user, group)
52 #print '# File belongs to user %s, group %s' % (user, group)
53 #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
53 #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
54 kind = ('different', 'same')
54 kind = ('different', 'same')
55 who = ('', 'user', 'group', 'user and the group')
55 who = ('', 'user', 'group', 'user and the group')
56 trusted = who[(user in tusers) + 2*(group in tgroups)]
56 trusted = who[(user in tusers) + 2*(group in tgroups)]
57 if trusted:
57 if trusted:
58 trusted = ', but we trust the ' + trusted
58 trusted = ', but we trust the ' + trusted
59 print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
59 print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
60 trusted)
60 trusted)
61
61
62 parentui = ui.ui()
62 parentui = ui.ui()
63 parentui.setconfig('ui', 'debug', str(bool(debug)))
63 parentui.setconfig('ui', 'debug', str(bool(debug)))
64 u = ui.ui(parentui=parentui)
64 u = ui.ui(parentui=parentui)
65 u.readconfig('.hg/hgrc')
65 u.readconfig('.hg/hgrc')
66 if silent:
66 if silent:
67 return u
67 return u
68 print 'trusted'
68 print 'trusted'
69 for name, path in u.configitems('paths'):
69 for name, path in u.configitems('paths'):
70 print ' ', name, '=', path
70 print ' ', name, '=', path
71 print 'untrusted'
71 print 'untrusted'
72 for name, path in u.configitems('paths', untrusted=True):
72 for name, path in u.configitems('paths', untrusted=True):
73 print '.',
73 print '.',
74 u.config('paths', name) # warning with debug=True
74 u.config('paths', name) # warning with debug=True
75 print '.',
75 print '.',
76 u.config('paths', name, untrusted=True) # no warnings
76 u.config('paths', name, untrusted=True) # no warnings
77 print name, '=', path
77 print name, '=', path
78 print
78 print
79
79
80 return u
80 return u
81
81
82 os.mkdir('repo')
82 os.mkdir('repo')
83 os.chdir('repo')
83 os.chdir('repo')
84 os.mkdir('.hg')
84 os.mkdir('.hg')
85 f = open('.hg/hgrc', 'w')
85 f = open('.hg/hgrc', 'w')
86 f.write('[paths]\n')
86 f.write('[paths]\n')
87 f.write('local = /another/path\n\n')
87 f.write('local = /another/path\n\n')
88 f.write('interpolated = %(global)s%(local)s\n\n')
89 f.close()
88 f.close()
90
89
91 #print '# Everything is run by user foo, group bar\n'
90 #print '# Everything is run by user foo, group bar\n'
92
91
93 # same user, same group
92 # same user, same group
94 testui()
93 testui()
95 # same user, different group
94 # same user, different group
96 testui(group='def')
95 testui(group='def')
97 # different user, same group
96 # different user, same group
98 testui(user='abc')
97 testui(user='abc')
99 # ... but we trust the group
98 # ... but we trust the group
100 testui(user='abc', tgroups=['bar'])
99 testui(user='abc', tgroups=['bar'])
101 # different user, different group
100 # different user, different group
102 testui(user='abc', group='def')
101 testui(user='abc', group='def')
103 # ... but we trust the user
102 # ... but we trust the user
104 testui(user='abc', group='def', tusers=['abc'])
103 testui(user='abc', group='def', tusers=['abc'])
105 # ... but we trust the group
104 # ... but we trust the group
106 testui(user='abc', group='def', tgroups=['def'])
105 testui(user='abc', group='def', tgroups=['def'])
107 # ... but we trust the user and the group
106 # ... but we trust the user and the group
108 testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
107 testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
109 # ... but we trust all users
108 # ... but we trust all users
110 print '# we trust all users'
109 print '# we trust all users'
111 testui(user='abc', group='def', tusers=['*'])
110 testui(user='abc', group='def', tusers=['*'])
112 # ... but we trust all groups
111 # ... but we trust all groups
113 print '# we trust all groups'
112 print '# we trust all groups'
114 testui(user='abc', group='def', tgroups=['*'])
113 testui(user='abc', group='def', tgroups=['*'])
115 # ... but we trust the whole universe
114 # ... but we trust the whole universe
116 print '# we trust all users and groups'
115 print '# we trust all users and groups'
117 testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
116 testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
118 # ... check that users and groups are in different namespaces
117 # ... check that users and groups are in different namespaces
119 print "# we don't get confused by users and groups with the same name"
118 print "# we don't get confused by users and groups with the same name"
120 testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
119 testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
121 # ... lists of user names work
120 # ... lists of user names work
122 print "# list of user names"
121 print "# list of user names"
123 testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
122 testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
124 tgroups=['bar', 'baz', 'qux'])
123 tgroups=['bar', 'baz', 'qux'])
125 # ... lists of group names work
124 # ... lists of group names work
126 print "# list of group names"
125 print "# list of group names"
127 testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
126 testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
128 tgroups=['bar', 'def', 'baz', 'qux'])
127 tgroups=['bar', 'def', 'baz', 'qux'])
129
128
130 print "# Can't figure out the name of the user running this process"
129 print "# Can't figure out the name of the user running this process"
131 testui(user='abc', group='def', cuser=None)
130 testui(user='abc', group='def', cuser=None)
132
131
133 print "# prints debug warnings"
132 print "# prints debug warnings"
134 u = testui(user='abc', group='def', cuser='foo', debug=True)
133 u = testui(user='abc', group='def', cuser='foo', debug=True)
135
134
136 print "# ui.readconfig sections"
135 print "# ui.readconfig sections"
137 filename = 'foobar'
136 filename = 'foobar'
138 f = open(filename, 'w')
137 f = open(filename, 'w')
139 f.write('[foobar]\n')
138 f.write('[foobar]\n')
140 f.write('baz = quux\n')
139 f.write('baz = quux\n')
141 f.close()
140 f.close()
142 u.readconfig(filename, sections = ['foobar'])
141 u.readconfig(filename, sections = ['foobar'])
143 print u.config('foobar', 'baz')
142 print u.config('foobar', 'baz')
144
143
145 print
144 print
146 print "# read trusted, untrusted, new ui, trusted"
145 print "# read trusted, untrusted, new ui, trusted"
147 u = ui.ui()
146 u = ui.ui()
148 u.setconfig('ui', 'debug', 'on')
147 u.setconfig('ui', 'debug', 'on')
149 u.readconfig(filename)
148 u.readconfig(filename)
150 u2 = ui.ui(parentui=u)
149 u2 = ui.ui(parentui=u)
151 def username(uid=None):
150 def username(uid=None):
152 return 'foo'
151 return 'foo'
153 util.username = username
152 util.username = username
154 u2.readconfig('.hg/hgrc')
153 u2.readconfig('.hg/hgrc')
155 print 'trusted:'
154 print 'trusted:'
156 print u2.config('foobar', 'baz')
155 print u2.config('foobar', 'baz')
157 print u2.config('paths', 'interpolated')
158 print 'untrusted:'
156 print 'untrusted:'
159 print u2.config('foobar', 'baz', untrusted=True)
157 print u2.config('foobar', 'baz', untrusted=True)
160 print u2.config('paths', 'interpolated', untrusted=True)
161
158
162 print
159 print
163 print "# error handling"
160 print "# error handling"
164
161
165 def assertraises(f, exc=util.Abort):
162 def assertraises(f, exc=util.Abort):
166 try:
163 try:
167 f()
164 f()
168 except exc, inst:
165 except exc, inst:
169 print 'raised', inst.__class__.__name__
166 print 'raised', inst.__class__.__name__
170 else:
167 else:
171 print 'no exception?!'
168 print 'no exception?!'
172
169
173 print "# file doesn't exist"
170 print "# file doesn't exist"
174 os.unlink('.hg/hgrc')
171 os.unlink('.hg/hgrc')
175 assert not os.path.exists('.hg/hgrc')
172 assert not os.path.exists('.hg/hgrc')
176 testui(debug=True, silent=True)
173 testui(debug=True, silent=True)
177 testui(user='abc', group='def', debug=True, silent=True)
174 testui(user='abc', group='def', debug=True, silent=True)
178
175
179 print
176 print
180 print "# parse error"
177 print "# parse error"
181 f = open('.hg/hgrc', 'w')
178 f = open('.hg/hgrc', 'w')
182 f.write('foo = bar')
179 f.write('foo')
183 f.close()
184 testui(user='abc', group='def', silent=True)
185 assertraises(lambda: testui(debug=True, silent=True))
186
187 print
188 print "# interpolation error"
189 f = open('.hg/hgrc', 'w')
190 f.write('[foo]\n')
191 f.write('bar = %(')
192 f.close()
180 f.close()
193 u = testui(debug=True, silent=True)
194 print '# regular config:'
195 print ' trusted',
196 assertraises(lambda: u.config('foo', 'bar'))
197 print 'untrusted',
198 assertraises(lambda: u.config('foo', 'bar', untrusted=True))
199
181
200 u = testui(user='abc', group='def', debug=True, silent=True)
182 try:
201 print ' trusted ',
183 testui(user='abc', group='def', silent=True)
202 print u.config('foo', 'bar')
184 except error.ConfigError, inst:
203 print 'untrusted',
185 print inst
204 assertraises(lambda: u.config('foo', 'bar', untrusted=True))
205
186
206 print '# configitems:'
187 try:
207 print ' trusted ',
188 testui(debug=True, silent=True)
208 print u.configitems('foo')
189 except error.ConfigError, inst:
209 print 'untrusted',
190 print inst
210 assertraises(lambda: u.configitems('foo', untrusted=True))
211
@@ -1,211 +1,160 b''
1 # same user, same group
1 # same user, same group
2 trusted
2 trusted
3 global = /some/path
3 global = /some/path
4 interpolated = /some/path/another/path
5 local = /another/path
4 local = /another/path
6 untrusted
5 untrusted
7 . . global = /some/path
6 . . global = /some/path
8 . . interpolated = /some/path/another/path
9 . . local = /another/path
7 . . local = /another/path
10
8
11 # same user, different group
9 # same user, different group
12 trusted
10 trusted
13 global = /some/path
11 global = /some/path
14 interpolated = /some/path/another/path
15 local = /another/path
12 local = /another/path
16 untrusted
13 untrusted
17 . . global = /some/path
14 . . global = /some/path
18 . . interpolated = /some/path/another/path
19 . . local = /another/path
15 . . local = /another/path
20
16
21 # different user, same group
17 # different user, same group
22 Not trusting file .hg/hgrc from untrusted user abc, group bar
18 Not trusting file .hg/hgrc from untrusted user abc, group bar
23 trusted
19 trusted
24 global = /some/path
20 global = /some/path
25 untrusted
21 untrusted
26 . . global = /some/path
22 . . global = /some/path
27 . . interpolated = /some/path/another/path
28 . . local = /another/path
23 . . local = /another/path
29
24
30 # different user, same group, but we trust the group
25 # different user, same group, but we trust the group
31 trusted
26 trusted
32 global = /some/path
27 global = /some/path
33 interpolated = /some/path/another/path
34 local = /another/path
28 local = /another/path
35 untrusted
29 untrusted
36 . . global = /some/path
30 . . global = /some/path
37 . . interpolated = /some/path/another/path
38 . . local = /another/path
31 . . local = /another/path
39
32
40 # different user, different group
33 # different user, different group
41 Not trusting file .hg/hgrc from untrusted user abc, group def
34 Not trusting file .hg/hgrc from untrusted user abc, group def
42 trusted
35 trusted
43 global = /some/path
36 global = /some/path
44 untrusted
37 untrusted
45 . . global = /some/path
38 . . global = /some/path
46 . . interpolated = /some/path/another/path
47 . . local = /another/path
39 . . local = /another/path
48
40
49 # different user, different group, but we trust the user
41 # different user, different group, but we trust the user
50 trusted
42 trusted
51 global = /some/path
43 global = /some/path
52 interpolated = /some/path/another/path
53 local = /another/path
44 local = /another/path
54 untrusted
45 untrusted
55 . . global = /some/path
46 . . global = /some/path
56 . . interpolated = /some/path/another/path
57 . . local = /another/path
47 . . local = /another/path
58
48
59 # different user, different group, but we trust the group
49 # different user, different group, but we trust the group
60 trusted
50 trusted
61 global = /some/path
51 global = /some/path
62 interpolated = /some/path/another/path
63 local = /another/path
52 local = /another/path
64 untrusted
53 untrusted
65 . . global = /some/path
54 . . global = /some/path
66 . . interpolated = /some/path/another/path
67 . . local = /another/path
55 . . local = /another/path
68
56
69 # different user, different group, but we trust the user and the group
57 # different user, different group, but we trust the user and the group
70 trusted
58 trusted
71 global = /some/path
59 global = /some/path
72 interpolated = /some/path/another/path
73 local = /another/path
60 local = /another/path
74 untrusted
61 untrusted
75 . . global = /some/path
62 . . global = /some/path
76 . . interpolated = /some/path/another/path
77 . . local = /another/path
63 . . local = /another/path
78
64
79 # we trust all users
65 # we trust all users
80 # different user, different group
66 # different user, different group
81 trusted
67 trusted
82 global = /some/path
68 global = /some/path
83 interpolated = /some/path/another/path
84 local = /another/path
69 local = /another/path
85 untrusted
70 untrusted
86 . . global = /some/path
71 . . global = /some/path
87 . . interpolated = /some/path/another/path
88 . . local = /another/path
72 . . local = /another/path
89
73
90 # we trust all groups
74 # we trust all groups
91 # different user, different group
75 # different user, different group
92 trusted
76 trusted
93 global = /some/path
77 global = /some/path
94 interpolated = /some/path/another/path
95 local = /another/path
78 local = /another/path
96 untrusted
79 untrusted
97 . . global = /some/path
80 . . global = /some/path
98 . . interpolated = /some/path/another/path
99 . . local = /another/path
81 . . local = /another/path
100
82
101 # we trust all users and groups
83 # we trust all users and groups
102 # different user, different group
84 # different user, different group
103 trusted
85 trusted
104 global = /some/path
86 global = /some/path
105 interpolated = /some/path/another/path
106 local = /another/path
87 local = /another/path
107 untrusted
88 untrusted
108 . . global = /some/path
89 . . global = /some/path
109 . . interpolated = /some/path/another/path
110 . . local = /another/path
90 . . local = /another/path
111
91
112 # we don't get confused by users and groups with the same name
92 # we don't get confused by users and groups with the same name
113 # different user, different group
93 # different user, different group
114 Not trusting file .hg/hgrc from untrusted user abc, group def
94 Not trusting file .hg/hgrc from untrusted user abc, group def
115 trusted
95 trusted
116 global = /some/path
96 global = /some/path
117 untrusted
97 untrusted
118 . . global = /some/path
98 . . global = /some/path
119 . . interpolated = /some/path/another/path
120 . . local = /another/path
99 . . local = /another/path
121
100
122 # list of user names
101 # list of user names
123 # different user, different group, but we trust the user
102 # different user, different group, but we trust the user
124 trusted
103 trusted
125 global = /some/path
104 global = /some/path
126 interpolated = /some/path/another/path
127 local = /another/path
105 local = /another/path
128 untrusted
106 untrusted
129 . . global = /some/path
107 . . global = /some/path
130 . . interpolated = /some/path/another/path
131 . . local = /another/path
108 . . local = /another/path
132
109
133 # list of group names
110 # list of group names
134 # different user, different group, but we trust the group
111 # different user, different group, but we trust the group
135 trusted
112 trusted
136 global = /some/path
113 global = /some/path
137 interpolated = /some/path/another/path
138 local = /another/path
114 local = /another/path
139 untrusted
115 untrusted
140 . . global = /some/path
116 . . global = /some/path
141 . . interpolated = /some/path/another/path
142 . . local = /another/path
117 . . local = /another/path
143
118
144 # Can't figure out the name of the user running this process
119 # Can't figure out the name of the user running this process
145 # different user, different group
120 # different user, different group
146 Not trusting file .hg/hgrc from untrusted user abc, group def
121 Not trusting file .hg/hgrc from untrusted user abc, group def
147 trusted
122 trusted
148 global = /some/path
123 global = /some/path
149 untrusted
124 untrusted
150 . . global = /some/path
125 . . global = /some/path
151 . . interpolated = /some/path/another/path
152 . . local = /another/path
126 . . local = /another/path
153
127
154 # prints debug warnings
128 # prints debug warnings
155 # different user, different group
129 # different user, different group
156 Not trusting file .hg/hgrc from untrusted user abc, group def
130 Not trusting file .hg/hgrc from untrusted user abc, group def
157 trusted
131 trusted
158 Ignoring untrusted configuration option paths.interpolated = /some/path/another/path
159 Ignoring untrusted configuration option paths.local = /another/path
132 Ignoring untrusted configuration option paths.local = /another/path
160 global = /some/path
133 global = /some/path
161 untrusted
134 untrusted
162 . . global = /some/path
135 . . global = /some/path
163 .Ignoring untrusted configuration option paths.interpolated = /some/path/another/path
164 . interpolated = /some/path/another/path
165 .Ignoring untrusted configuration option paths.local = /another/path
136 .Ignoring untrusted configuration option paths.local = /another/path
166 . local = /another/path
137 . local = /another/path
167
138
168 # ui.readconfig sections
139 # ui.readconfig sections
169 quux
140 quux
170
141
171 # read trusted, untrusted, new ui, trusted
142 # read trusted, untrusted, new ui, trusted
172 Not trusting file foobar from untrusted user abc, group def
143 Not trusting file foobar from untrusted user abc, group def
173 trusted:
144 trusted:
174 Ignoring untrusted configuration option foobar.baz = quux
145 Ignoring untrusted configuration option foobar.baz = quux
175 None
146 None
176 /some/path/another/path
177 untrusted:
147 untrusted:
178 quux
148 quux
179 /some/path/another/path
180
149
181 # error handling
150 # error handling
182 # file doesn't exist
151 # file doesn't exist
183 # same user, same group
152 # same user, same group
184 # different user, different group
153 # different user, different group
185
154
186 # parse error
155 # parse error
187 # different user, different group
156 # different user, different group
188 Not trusting file .hg/hgrc from untrusted user abc, group def
157 Not trusting file .hg/hgrc from untrusted user abc, group def
189 Ignored: Failed to parse .hg/hgrc
158 Ignored: config error at .hg/hgrc:1: 'foo'
190 File contains no section headers.
191 file: .hg/hgrc, line: 1
192 'foo = bar'
193 # same user, same group
194 raised Abort
195
196 # interpolation error
197 # same user, same group
159 # same user, same group
198 # regular config:
160 config error at .hg/hgrc:1: 'foo'
199 trusted raised Abort
200 untrusted raised Abort
201 # different user, different group
202 Not trusting file .hg/hgrc from untrusted user abc, group def
203 trusted Ignored: Error in configuration section [foo] parameter 'bar':
204 bad interpolation variable reference '%('
205 None
206 untrusted raised Abort
207 # configitems:
208 trusted Ignored: Error in configuration section [foo]:
209 bad interpolation variable reference '%('
210 []
211 untrusted raised Abort
@@ -1,90 +1,55 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 import ConfigParser
3 from mercurial import ui, util, dispatch, error
4 from mercurial import ui, util, dispatch
5
4
6 testui = ui.ui()
5 testui = ui.ui()
7 parsed = dispatch._parseconfig(testui, [
6 parsed = dispatch._parseconfig(testui, [
8 'values.string=string value',
7 'values.string=string value',
9 'values.bool1=true',
8 'values.bool1=true',
10 'values.bool2=false',
9 'values.bool2=false',
11 'lists.list1=foo',
10 'lists.list1=foo',
12 'lists.list2=foo bar baz',
11 'lists.list2=foo bar baz',
13 'lists.list3=alice, bob',
12 'lists.list3=alice, bob',
14 'lists.list4=foo bar baz alice, bob',
13 'lists.list4=foo bar baz alice, bob',
15 'interpolation.value1=hallo',
16 'interpolation.value2=%(value1)s world',
17 'interpolation.value3=%(novalue)s',
18 'interpolation.value4=%(bad)1',
19 'interpolation.value5=%bad2',
20 ])
14 ])
21
15
22 print repr(testui.configitems('values'))
16 print repr(testui.configitems('values'))
23 print repr(testui.configitems('lists'))
17 print repr(testui.configitems('lists'))
24 try:
25 print repr(testui.configitems('interpolation'))
26 except util.Abort, inst:
27 print inst
28 print "---"
18 print "---"
29 print repr(testui.config('values', 'string'))
19 print repr(testui.config('values', 'string'))
30 print repr(testui.config('values', 'bool1'))
20 print repr(testui.config('values', 'bool1'))
31 print repr(testui.config('values', 'bool2'))
21 print repr(testui.config('values', 'bool2'))
32 print repr(testui.config('values', 'unknown'))
22 print repr(testui.config('values', 'unknown'))
33 print "---"
23 print "---"
34 try:
24 try:
35 print repr(testui.configbool('values', 'string'))
25 print repr(testui.configbool('values', 'string'))
36 except util.Abort, inst:
26 except error.ConfigError, inst:
37 print inst
27 print inst
38 print repr(testui.configbool('values', 'bool1'))
28 print repr(testui.configbool('values', 'bool1'))
39 print repr(testui.configbool('values', 'bool2'))
29 print repr(testui.configbool('values', 'bool2'))
40 print repr(testui.configbool('values', 'bool2', True))
30 print repr(testui.configbool('values', 'bool2', True))
41 print repr(testui.configbool('values', 'unknown'))
31 print repr(testui.configbool('values', 'unknown'))
42 print repr(testui.configbool('values', 'unknown', True))
32 print repr(testui.configbool('values', 'unknown', True))
43 print "---"
33 print "---"
44 print repr(testui.configlist('lists', 'list1'))
34 print repr(testui.configlist('lists', 'list1'))
45 print repr(testui.configlist('lists', 'list2'))
35 print repr(testui.configlist('lists', 'list2'))
46 print repr(testui.configlist('lists', 'list3'))
36 print repr(testui.configlist('lists', 'list3'))
47 print repr(testui.configlist('lists', 'list4'))
37 print repr(testui.configlist('lists', 'list4'))
48 print repr(testui.configlist('lists', 'list4', ['foo']))
38 print repr(testui.configlist('lists', 'list4', ['foo']))
49 print repr(testui.configlist('lists', 'unknown'))
39 print repr(testui.configlist('lists', 'unknown'))
50 print repr(testui.configlist('lists', 'unknown', ''))
40 print repr(testui.configlist('lists', 'unknown', ''))
51 print repr(testui.configlist('lists', 'unknown', 'foo'))
41 print repr(testui.configlist('lists', 'unknown', 'foo'))
52 print repr(testui.configlist('lists', 'unknown', ['foo']))
42 print repr(testui.configlist('lists', 'unknown', ['foo']))
53 print repr(testui.configlist('lists', 'unknown', 'foo bar'))
43 print repr(testui.configlist('lists', 'unknown', 'foo bar'))
54 print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
44 print repr(testui.configlist('lists', 'unknown', 'foo, bar'))
55 print repr(testui.configlist('lists', 'unknown', ['foo bar']))
45 print repr(testui.configlist('lists', 'unknown', ['foo bar']))
56 print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
46 print repr(testui.configlist('lists', 'unknown', ['foo', 'bar']))
57 print "---"
58 print repr(testui.config('interpolation', 'value1'))
59 print repr(testui.config('interpolation', 'value2'))
60 try:
61 print repr(testui.config('interpolation', 'value3'))
62 except util.Abort, inst:
63 print inst
64 try:
65 print repr(testui.config('interpolation', 'value4'))
66 except util.Abort, inst:
67 print inst
68 try:
69 print repr(testui.config('interpolation', 'value5'))
70 except util.Abort, inst:
71 print inst
72 print "---"
73
47
74 cp = util.configparser()
48 print repr(testui.config('values', 'String'))
75 cp.add_section('foo')
76 cp.set('foo', 'bar', 'baz')
77 try:
78 # should fail - keys are case-sensitive
79 cp.get('foo', 'Bar')
80 except ConfigParser.NoOptionError, inst:
81 print inst
82
49
83 def function():
50 def function():
84 pass
51 pass
85
52
86 cp.add_section('hook')
87 # values that aren't strings should work
53 # values that aren't strings should work
88 cp.set('hook', 'commit', function)
54 testui.setconfig('hook', 'commit', function)
89 f = cp.get('hook', 'commit')
55 print function == testui.config('hook', 'commit')
90 print "f %s= function" % (f == function and '=' or '!')
@@ -1,48 +1,30 b''
1 [('bool1', 'true'), ('bool2', 'false'), ('string', 'string value')]
1 [('string', 'string value'), ('bool1', 'true'), ('bool2', 'false')]
2 [('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob')]
2 [('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob')]
3 Error in configuration section [interpolation]:
4 '%' must be followed by '%' or '(', found: '%bad2'
5 ---
3 ---
6 'string value'
4 'string value'
7 'true'
5 'true'
8 'false'
6 'false'
9 None
7 None
10 ---
8 ---
11 Error in configuration section [values] parameter 'string':
9 values.string not a boolean ('string value')
12 Not a boolean: string value
13 True
10 True
14 False
11 False
15 False
12 False
16 False
13 False
17 True
14 True
18 ---
15 ---
19 ['foo']
16 ['foo']
20 ['foo', 'bar', 'baz']
17 ['foo', 'bar', 'baz']
21 ['alice', 'bob']
18 ['alice', 'bob']
22 ['foo', 'bar', 'baz', 'alice', 'bob']
19 ['foo', 'bar', 'baz', 'alice', 'bob']
23 ['foo', 'bar', 'baz', 'alice', 'bob']
20 ['foo', 'bar', 'baz', 'alice', 'bob']
24 []
21 []
25 []
22 []
26 ['foo']
23 ['foo']
27 ['foo']
24 ['foo']
28 ['foo', 'bar']
25 ['foo', 'bar']
29 ['foo', 'bar']
26 ['foo', 'bar']
30 ['foo bar']
27 ['foo bar']
31 ['foo', 'bar']
28 ['foo', 'bar']
32 ---
29 None
33 'hallo'
30 True
34 'hallo world'
35 Error in configuration section [interpolation] parameter 'value3':
36 Bad value substitution:
37 section: [interpolation]
38 option : value3
39 key : novalue
40 rawval :
41
42 Error in configuration section [interpolation] parameter 'value4':
43 bad interpolation variable reference '%(bad)1'
44 Error in configuration section [interpolation] parameter 'value5':
45 '%' must be followed by '%' or '(', found: '%bad2'
46 ---
47 No option 'Bar' in section: 'foo'
48 f == function
General Comments 0
You need to be logged in to leave comments. Login now