##// END OF EJS Templates
ui: lowercase "not trusting file" warning message
Martin Geisler -
r16939:fa91ddfc default
parent child Browse files
Show More
@@ -1,759 +1,759
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 or any later version.
6 # GNU General Public License version 2 or any later version.
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, scmutil, util, error, formatter
10 import config, scmutil, util, error, formatter
11
11
12 class ui(object):
12 class ui(object):
13 def __init__(self, src=None):
13 def __init__(self, src=None):
14 self._buffers = []
14 self._buffers = []
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
16 self._reportuntrusted = True
16 self._reportuntrusted = True
17 self._ocfg = config.config() # overlay
17 self._ocfg = config.config() # overlay
18 self._tcfg = config.config() # trusted
18 self._tcfg = config.config() # trusted
19 self._ucfg = config.config() # untrusted
19 self._ucfg = config.config() # untrusted
20 self._trustusers = set()
20 self._trustusers = set()
21 self._trustgroups = set()
21 self._trustgroups = set()
22
22
23 if src:
23 if src:
24 self.fout = src.fout
24 self.fout = src.fout
25 self.ferr = src.ferr
25 self.ferr = src.ferr
26 self.fin = src.fin
26 self.fin = src.fin
27
27
28 self._tcfg = src._tcfg.copy()
28 self._tcfg = src._tcfg.copy()
29 self._ucfg = src._ucfg.copy()
29 self._ucfg = src._ucfg.copy()
30 self._ocfg = src._ocfg.copy()
30 self._ocfg = src._ocfg.copy()
31 self._trustusers = src._trustusers.copy()
31 self._trustusers = src._trustusers.copy()
32 self._trustgroups = src._trustgroups.copy()
32 self._trustgroups = src._trustgroups.copy()
33 self.environ = src.environ
33 self.environ = src.environ
34 self.fixconfig()
34 self.fixconfig()
35 else:
35 else:
36 self.fout = sys.stdout
36 self.fout = sys.stdout
37 self.ferr = sys.stderr
37 self.ferr = sys.stderr
38 self.fin = sys.stdin
38 self.fin = sys.stdin
39
39
40 # shared read-only environment
40 # shared read-only environment
41 self.environ = os.environ
41 self.environ = os.environ
42 # we always trust global config files
42 # we always trust global config files
43 for f in scmutil.rcpath():
43 for f in scmutil.rcpath():
44 self.readconfig(f, trust=True)
44 self.readconfig(f, trust=True)
45
45
46 def copy(self):
46 def copy(self):
47 return self.__class__(self)
47 return self.__class__(self)
48
48
49 def formatter(self, topic, opts):
49 def formatter(self, topic, opts):
50 return formatter.formatter(self, topic, opts)
50 return formatter.formatter(self, topic, opts)
51
51
52 def _trusted(self, fp, f):
52 def _trusted(self, fp, f):
53 st = util.fstat(fp)
53 st = util.fstat(fp)
54 if util.isowner(st):
54 if util.isowner(st):
55 return True
55 return True
56
56
57 tusers, tgroups = self._trustusers, self._trustgroups
57 tusers, tgroups = self._trustusers, self._trustgroups
58 if '*' in tusers or '*' in tgroups:
58 if '*' in tusers or '*' in tgroups:
59 return True
59 return True
60
60
61 user = util.username(st.st_uid)
61 user = util.username(st.st_uid)
62 group = util.groupname(st.st_gid)
62 group = util.groupname(st.st_gid)
63 if user in tusers or group in tgroups or user == util.username():
63 if user in tusers or group in tgroups or user == util.username():
64 return True
64 return True
65
65
66 if self._reportuntrusted:
66 if self._reportuntrusted:
67 self.warn(_('Not trusting file %s from untrusted '
67 self.warn(_('not trusting file %s from untrusted '
68 'user %s, group %s\n') % (f, user, group))
68 'user %s, group %s\n') % (f, user, group))
69 return False
69 return False
70
70
71 def readconfig(self, filename, root=None, trust=False,
71 def readconfig(self, filename, root=None, trust=False,
72 sections=None, remap=None):
72 sections=None, remap=None):
73 try:
73 try:
74 fp = open(filename)
74 fp = open(filename)
75 except IOError:
75 except IOError:
76 if not sections: # ignore unless we were looking for something
76 if not sections: # ignore unless we were looking for something
77 return
77 return
78 raise
78 raise
79
79
80 cfg = config.config()
80 cfg = config.config()
81 trusted = sections or trust or self._trusted(fp, filename)
81 trusted = sections or trust or self._trusted(fp, filename)
82
82
83 try:
83 try:
84 cfg.read(filename, fp, sections=sections, remap=remap)
84 cfg.read(filename, fp, sections=sections, remap=remap)
85 fp.close()
85 fp.close()
86 except error.ConfigError, inst:
86 except error.ConfigError, inst:
87 if trusted:
87 if trusted:
88 raise
88 raise
89 self.warn(_("ignored: %s\n") % str(inst))
89 self.warn(_("ignored: %s\n") % str(inst))
90
90
91 if self.plain():
91 if self.plain():
92 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
92 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
93 'logtemplate', 'style',
93 'logtemplate', 'style',
94 'traceback', 'verbose'):
94 'traceback', 'verbose'):
95 if k in cfg['ui']:
95 if k in cfg['ui']:
96 del cfg['ui'][k]
96 del cfg['ui'][k]
97 for k, v in cfg.items('defaults'):
97 for k, v in cfg.items('defaults'):
98 del cfg['defaults'][k]
98 del cfg['defaults'][k]
99 # Don't remove aliases from the configuration if in the exceptionlist
99 # Don't remove aliases from the configuration if in the exceptionlist
100 if self.plain('alias'):
100 if self.plain('alias'):
101 for k, v in cfg.items('alias'):
101 for k, v in cfg.items('alias'):
102 del cfg['alias'][k]
102 del cfg['alias'][k]
103
103
104 if trusted:
104 if trusted:
105 self._tcfg.update(cfg)
105 self._tcfg.update(cfg)
106 self._tcfg.update(self._ocfg)
106 self._tcfg.update(self._ocfg)
107 self._ucfg.update(cfg)
107 self._ucfg.update(cfg)
108 self._ucfg.update(self._ocfg)
108 self._ucfg.update(self._ocfg)
109
109
110 if root is None:
110 if root is None:
111 root = os.path.expanduser('~')
111 root = os.path.expanduser('~')
112 self.fixconfig(root=root)
112 self.fixconfig(root=root)
113
113
114 def fixconfig(self, root=None, section=None):
114 def fixconfig(self, root=None, section=None):
115 if section in (None, 'paths'):
115 if section in (None, 'paths'):
116 # expand vars and ~
116 # expand vars and ~
117 # translate paths relative to root (or home) into absolute paths
117 # translate paths relative to root (or home) into absolute paths
118 root = root or os.getcwd()
118 root = root or os.getcwd()
119 for c in self._tcfg, self._ucfg, self._ocfg:
119 for c in self._tcfg, self._ucfg, self._ocfg:
120 for n, p in c.items('paths'):
120 for n, p in c.items('paths'):
121 if not p:
121 if not p:
122 continue
122 continue
123 if '%%' in p:
123 if '%%' in p:
124 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
124 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
125 % (n, p, self.configsource('paths', n)))
125 % (n, p, self.configsource('paths', n)))
126 p = p.replace('%%', '%')
126 p = p.replace('%%', '%')
127 p = util.expandpath(p)
127 p = util.expandpath(p)
128 if not util.hasscheme(p) and not os.path.isabs(p):
128 if not util.hasscheme(p) and not os.path.isabs(p):
129 p = os.path.normpath(os.path.join(root, p))
129 p = os.path.normpath(os.path.join(root, p))
130 c.set("paths", n, p)
130 c.set("paths", n, p)
131
131
132 if section in (None, 'ui'):
132 if section in (None, 'ui'):
133 # update ui options
133 # update ui options
134 self.debugflag = self.configbool('ui', 'debug')
134 self.debugflag = self.configbool('ui', 'debug')
135 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
135 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
136 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
136 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
137 if self.verbose and self.quiet:
137 if self.verbose and self.quiet:
138 self.quiet = self.verbose = False
138 self.quiet = self.verbose = False
139 self._reportuntrusted = self.debugflag or self.configbool("ui",
139 self._reportuntrusted = self.debugflag or self.configbool("ui",
140 "report_untrusted", True)
140 "report_untrusted", True)
141 self.tracebackflag = self.configbool('ui', 'traceback', False)
141 self.tracebackflag = self.configbool('ui', 'traceback', False)
142
142
143 if section in (None, 'trusted'):
143 if section in (None, 'trusted'):
144 # update trust information
144 # update trust information
145 self._trustusers.update(self.configlist('trusted', 'users'))
145 self._trustusers.update(self.configlist('trusted', 'users'))
146 self._trustgroups.update(self.configlist('trusted', 'groups'))
146 self._trustgroups.update(self.configlist('trusted', 'groups'))
147
147
148 def backupconfig(self, section, item):
148 def backupconfig(self, section, item):
149 return (self._ocfg.backup(section, item),
149 return (self._ocfg.backup(section, item),
150 self._tcfg.backup(section, item),
150 self._tcfg.backup(section, item),
151 self._ucfg.backup(section, item),)
151 self._ucfg.backup(section, item),)
152 def restoreconfig(self, data):
152 def restoreconfig(self, data):
153 self._ocfg.restore(data[0])
153 self._ocfg.restore(data[0])
154 self._tcfg.restore(data[1])
154 self._tcfg.restore(data[1])
155 self._ucfg.restore(data[2])
155 self._ucfg.restore(data[2])
156
156
157 def setconfig(self, section, name, value, overlay=True):
157 def setconfig(self, section, name, value, overlay=True):
158 if overlay:
158 if overlay:
159 self._ocfg.set(section, name, value)
159 self._ocfg.set(section, name, value)
160 self._tcfg.set(section, name, value)
160 self._tcfg.set(section, name, value)
161 self._ucfg.set(section, name, value)
161 self._ucfg.set(section, name, value)
162 self.fixconfig(section=section)
162 self.fixconfig(section=section)
163
163
164 def _data(self, untrusted):
164 def _data(self, untrusted):
165 return untrusted and self._ucfg or self._tcfg
165 return untrusted and self._ucfg or self._tcfg
166
166
167 def configsource(self, section, name, untrusted=False):
167 def configsource(self, section, name, untrusted=False):
168 return self._data(untrusted).source(section, name) or 'none'
168 return self._data(untrusted).source(section, name) or 'none'
169
169
170 def config(self, section, name, default=None, untrusted=False):
170 def config(self, section, name, default=None, untrusted=False):
171 if isinstance(name, list):
171 if isinstance(name, list):
172 alternates = name
172 alternates = name
173 else:
173 else:
174 alternates = [name]
174 alternates = [name]
175
175
176 for n in alternates:
176 for n in alternates:
177 value = self._data(untrusted).get(section, name, None)
177 value = self._data(untrusted).get(section, name, None)
178 if value is not None:
178 if value is not None:
179 name = n
179 name = n
180 break
180 break
181 else:
181 else:
182 value = default
182 value = default
183
183
184 if self.debugflag and not untrusted and self._reportuntrusted:
184 if self.debugflag and not untrusted and self._reportuntrusted:
185 uvalue = self._ucfg.get(section, name)
185 uvalue = self._ucfg.get(section, name)
186 if uvalue is not None and uvalue != value:
186 if uvalue is not None and uvalue != value:
187 self.debug("ignoring untrusted configuration option "
187 self.debug("ignoring untrusted configuration option "
188 "%s.%s = %s\n" % (section, name, uvalue))
188 "%s.%s = %s\n" % (section, name, uvalue))
189 return value
189 return value
190
190
191 def configpath(self, section, name, default=None, untrusted=False):
191 def configpath(self, section, name, default=None, untrusted=False):
192 'get a path config item, expanded relative to repo root or config file'
192 'get a path config item, expanded relative to repo root or config file'
193 v = self.config(section, name, default, untrusted)
193 v = self.config(section, name, default, untrusted)
194 if v is None:
194 if v is None:
195 return None
195 return None
196 if not os.path.isabs(v) or "://" not in v:
196 if not os.path.isabs(v) or "://" not in v:
197 src = self.configsource(section, name, untrusted)
197 src = self.configsource(section, name, untrusted)
198 if ':' in src:
198 if ':' in src:
199 base = os.path.dirname(src.rsplit(':')[0])
199 base = os.path.dirname(src.rsplit(':')[0])
200 v = os.path.join(base, os.path.expanduser(v))
200 v = os.path.join(base, os.path.expanduser(v))
201 return v
201 return v
202
202
203 def configbool(self, section, name, default=False, untrusted=False):
203 def configbool(self, section, name, default=False, untrusted=False):
204 """parse a configuration element as a boolean
204 """parse a configuration element as a boolean
205
205
206 >>> u = ui(); s = 'foo'
206 >>> u = ui(); s = 'foo'
207 >>> u.setconfig(s, 'true', 'yes')
207 >>> u.setconfig(s, 'true', 'yes')
208 >>> u.configbool(s, 'true')
208 >>> u.configbool(s, 'true')
209 True
209 True
210 >>> u.setconfig(s, 'false', 'no')
210 >>> u.setconfig(s, 'false', 'no')
211 >>> u.configbool(s, 'false')
211 >>> u.configbool(s, 'false')
212 False
212 False
213 >>> u.configbool(s, 'unknown')
213 >>> u.configbool(s, 'unknown')
214 False
214 False
215 >>> u.configbool(s, 'unknown', True)
215 >>> u.configbool(s, 'unknown', True)
216 True
216 True
217 >>> u.setconfig(s, 'invalid', 'somevalue')
217 >>> u.setconfig(s, 'invalid', 'somevalue')
218 >>> u.configbool(s, 'invalid')
218 >>> u.configbool(s, 'invalid')
219 Traceback (most recent call last):
219 Traceback (most recent call last):
220 ...
220 ...
221 ConfigError: foo.invalid is not a boolean ('somevalue')
221 ConfigError: foo.invalid is not a boolean ('somevalue')
222 """
222 """
223
223
224 v = self.config(section, name, None, untrusted)
224 v = self.config(section, name, None, untrusted)
225 if v is None:
225 if v is None:
226 return default
226 return default
227 if isinstance(v, bool):
227 if isinstance(v, bool):
228 return v
228 return v
229 b = util.parsebool(v)
229 b = util.parsebool(v)
230 if b is None:
230 if b is None:
231 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
231 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
232 % (section, name, v))
232 % (section, name, v))
233 return b
233 return b
234
234
235 def configint(self, section, name, default=None, untrusted=False):
235 def configint(self, section, name, default=None, untrusted=False):
236 """parse a configuration element as an integer
236 """parse a configuration element as an integer
237
237
238 >>> u = ui(); s = 'foo'
238 >>> u = ui(); s = 'foo'
239 >>> u.setconfig(s, 'int1', '42')
239 >>> u.setconfig(s, 'int1', '42')
240 >>> u.configint(s, 'int1')
240 >>> u.configint(s, 'int1')
241 42
241 42
242 >>> u.setconfig(s, 'int2', '-42')
242 >>> u.setconfig(s, 'int2', '-42')
243 >>> u.configint(s, 'int2')
243 >>> u.configint(s, 'int2')
244 -42
244 -42
245 >>> u.configint(s, 'unknown', 7)
245 >>> u.configint(s, 'unknown', 7)
246 7
246 7
247 >>> u.setconfig(s, 'invalid', 'somevalue')
247 >>> u.setconfig(s, 'invalid', 'somevalue')
248 >>> u.configint(s, 'invalid')
248 >>> u.configint(s, 'invalid')
249 Traceback (most recent call last):
249 Traceback (most recent call last):
250 ...
250 ...
251 ConfigError: foo.invalid is not an integer ('somevalue')
251 ConfigError: foo.invalid is not an integer ('somevalue')
252 """
252 """
253
253
254 v = self.config(section, name, None, untrusted)
254 v = self.config(section, name, None, untrusted)
255 if v is None:
255 if v is None:
256 return default
256 return default
257 try:
257 try:
258 return int(v)
258 return int(v)
259 except ValueError:
259 except ValueError:
260 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
260 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
261 % (section, name, v))
261 % (section, name, v))
262
262
263 def configlist(self, section, name, default=None, untrusted=False):
263 def configlist(self, section, name, default=None, untrusted=False):
264 """parse a configuration element as a list of comma/space separated
264 """parse a configuration element as a list of comma/space separated
265 strings
265 strings
266
266
267 >>> u = ui(); s = 'foo'
267 >>> u = ui(); s = 'foo'
268 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
268 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
269 >>> u.configlist(s, 'list1')
269 >>> u.configlist(s, 'list1')
270 ['this', 'is', 'a small', 'test']
270 ['this', 'is', 'a small', 'test']
271 """
271 """
272
272
273 def _parse_plain(parts, s, offset):
273 def _parse_plain(parts, s, offset):
274 whitespace = False
274 whitespace = False
275 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
275 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
276 whitespace = True
276 whitespace = True
277 offset += 1
277 offset += 1
278 if offset >= len(s):
278 if offset >= len(s):
279 return None, parts, offset
279 return None, parts, offset
280 if whitespace:
280 if whitespace:
281 parts.append('')
281 parts.append('')
282 if s[offset] == '"' and not parts[-1]:
282 if s[offset] == '"' and not parts[-1]:
283 return _parse_quote, parts, offset + 1
283 return _parse_quote, parts, offset + 1
284 elif s[offset] == '"' and parts[-1][-1] == '\\':
284 elif s[offset] == '"' and parts[-1][-1] == '\\':
285 parts[-1] = parts[-1][:-1] + s[offset]
285 parts[-1] = parts[-1][:-1] + s[offset]
286 return _parse_plain, parts, offset + 1
286 return _parse_plain, parts, offset + 1
287 parts[-1] += s[offset]
287 parts[-1] += s[offset]
288 return _parse_plain, parts, offset + 1
288 return _parse_plain, parts, offset + 1
289
289
290 def _parse_quote(parts, s, offset):
290 def _parse_quote(parts, s, offset):
291 if offset < len(s) and s[offset] == '"': # ""
291 if offset < len(s) and s[offset] == '"': # ""
292 parts.append('')
292 parts.append('')
293 offset += 1
293 offset += 1
294 while offset < len(s) and (s[offset].isspace() or
294 while offset < len(s) and (s[offset].isspace() or
295 s[offset] == ','):
295 s[offset] == ','):
296 offset += 1
296 offset += 1
297 return _parse_plain, parts, offset
297 return _parse_plain, parts, offset
298
298
299 while offset < len(s) and s[offset] != '"':
299 while offset < len(s) and s[offset] != '"':
300 if (s[offset] == '\\' and offset + 1 < len(s)
300 if (s[offset] == '\\' and offset + 1 < len(s)
301 and s[offset + 1] == '"'):
301 and s[offset + 1] == '"'):
302 offset += 1
302 offset += 1
303 parts[-1] += '"'
303 parts[-1] += '"'
304 else:
304 else:
305 parts[-1] += s[offset]
305 parts[-1] += s[offset]
306 offset += 1
306 offset += 1
307
307
308 if offset >= len(s):
308 if offset >= len(s):
309 real_parts = _configlist(parts[-1])
309 real_parts = _configlist(parts[-1])
310 if not real_parts:
310 if not real_parts:
311 parts[-1] = '"'
311 parts[-1] = '"'
312 else:
312 else:
313 real_parts[0] = '"' + real_parts[0]
313 real_parts[0] = '"' + real_parts[0]
314 parts = parts[:-1]
314 parts = parts[:-1]
315 parts.extend(real_parts)
315 parts.extend(real_parts)
316 return None, parts, offset
316 return None, parts, offset
317
317
318 offset += 1
318 offset += 1
319 while offset < len(s) and s[offset] in [' ', ',']:
319 while offset < len(s) and s[offset] in [' ', ',']:
320 offset += 1
320 offset += 1
321
321
322 if offset < len(s):
322 if offset < len(s):
323 if offset + 1 == len(s) and s[offset] == '"':
323 if offset + 1 == len(s) and s[offset] == '"':
324 parts[-1] += '"'
324 parts[-1] += '"'
325 offset += 1
325 offset += 1
326 else:
326 else:
327 parts.append('')
327 parts.append('')
328 else:
328 else:
329 return None, parts, offset
329 return None, parts, offset
330
330
331 return _parse_plain, parts, offset
331 return _parse_plain, parts, offset
332
332
333 def _configlist(s):
333 def _configlist(s):
334 s = s.rstrip(' ,')
334 s = s.rstrip(' ,')
335 if not s:
335 if not s:
336 return []
336 return []
337 parser, parts, offset = _parse_plain, [''], 0
337 parser, parts, offset = _parse_plain, [''], 0
338 while parser:
338 while parser:
339 parser, parts, offset = parser(parts, s, offset)
339 parser, parts, offset = parser(parts, s, offset)
340 return parts
340 return parts
341
341
342 result = self.config(section, name, untrusted=untrusted)
342 result = self.config(section, name, untrusted=untrusted)
343 if result is None:
343 if result is None:
344 result = default or []
344 result = default or []
345 if isinstance(result, basestring):
345 if isinstance(result, basestring):
346 result = _configlist(result.lstrip(' ,\n'))
346 result = _configlist(result.lstrip(' ,\n'))
347 if result is None:
347 if result is None:
348 result = default or []
348 result = default or []
349 return result
349 return result
350
350
351 def has_section(self, section, untrusted=False):
351 def has_section(self, section, untrusted=False):
352 '''tell whether section exists in config.'''
352 '''tell whether section exists in config.'''
353 return section in self._data(untrusted)
353 return section in self._data(untrusted)
354
354
355 def configitems(self, section, untrusted=False):
355 def configitems(self, section, untrusted=False):
356 items = self._data(untrusted).items(section)
356 items = self._data(untrusted).items(section)
357 if self.debugflag and not untrusted and self._reportuntrusted:
357 if self.debugflag and not untrusted and self._reportuntrusted:
358 for k, v in self._ucfg.items(section):
358 for k, v in self._ucfg.items(section):
359 if self._tcfg.get(section, k) != v:
359 if self._tcfg.get(section, k) != v:
360 self.debug("ignoring untrusted configuration option "
360 self.debug("ignoring untrusted configuration option "
361 "%s.%s = %s\n" % (section, k, v))
361 "%s.%s = %s\n" % (section, k, v))
362 return items
362 return items
363
363
364 def walkconfig(self, untrusted=False):
364 def walkconfig(self, untrusted=False):
365 cfg = self._data(untrusted)
365 cfg = self._data(untrusted)
366 for section in cfg.sections():
366 for section in cfg.sections():
367 for name, value in self.configitems(section, untrusted):
367 for name, value in self.configitems(section, untrusted):
368 yield section, name, value
368 yield section, name, value
369
369
370 def plain(self, feature=None):
370 def plain(self, feature=None):
371 '''is plain mode active?
371 '''is plain mode active?
372
372
373 Plain mode means that all configuration variables which affect
373 Plain mode means that all configuration variables which affect
374 the behavior and output of Mercurial should be
374 the behavior and output of Mercurial should be
375 ignored. Additionally, the output should be stable,
375 ignored. Additionally, the output should be stable,
376 reproducible and suitable for use in scripts or applications.
376 reproducible and suitable for use in scripts or applications.
377
377
378 The only way to trigger plain mode is by setting either the
378 The only way to trigger plain mode is by setting either the
379 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
379 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
380
380
381 The return value can either be
381 The return value can either be
382 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
382 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
383 - True otherwise
383 - True otherwise
384 '''
384 '''
385 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
385 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
386 return False
386 return False
387 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
387 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
388 if feature and exceptions:
388 if feature and exceptions:
389 return feature not in exceptions
389 return feature not in exceptions
390 return True
390 return True
391
391
392 def username(self):
392 def username(self):
393 """Return default username to be used in commits.
393 """Return default username to be used in commits.
394
394
395 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
395 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
396 and stop searching if one of these is set.
396 and stop searching if one of these is set.
397 If not found and ui.askusername is True, ask the user, else use
397 If not found and ui.askusername is True, ask the user, else use
398 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
398 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
399 """
399 """
400 user = os.environ.get("HGUSER")
400 user = os.environ.get("HGUSER")
401 if user is None:
401 if user is None:
402 user = self.config("ui", "username")
402 user = self.config("ui", "username")
403 if user is not None:
403 if user is not None:
404 user = os.path.expandvars(user)
404 user = os.path.expandvars(user)
405 if user is None:
405 if user is None:
406 user = os.environ.get("EMAIL")
406 user = os.environ.get("EMAIL")
407 if user is None and self.configbool("ui", "askusername"):
407 if user is None and self.configbool("ui", "askusername"):
408 user = self.prompt(_("enter a commit username:"), default=None)
408 user = self.prompt(_("enter a commit username:"), default=None)
409 if user is None and not self.interactive():
409 if user is None and not self.interactive():
410 try:
410 try:
411 user = '%s@%s' % (util.getuser(), socket.getfqdn())
411 user = '%s@%s' % (util.getuser(), socket.getfqdn())
412 self.warn(_("No username found, using '%s' instead\n") % user)
412 self.warn(_("No username found, using '%s' instead\n") % user)
413 except KeyError:
413 except KeyError:
414 pass
414 pass
415 if not user:
415 if not user:
416 raise util.Abort(_('no username supplied (see "hg help config")'))
416 raise util.Abort(_('no username supplied (see "hg help config")'))
417 if "\n" in user:
417 if "\n" in user:
418 raise util.Abort(_("username %s contains a newline\n") % repr(user))
418 raise util.Abort(_("username %s contains a newline\n") % repr(user))
419 return user
419 return user
420
420
421 def shortuser(self, user):
421 def shortuser(self, user):
422 """Return a short representation of a user name or email address."""
422 """Return a short representation of a user name or email address."""
423 if not self.verbose:
423 if not self.verbose:
424 user = util.shortuser(user)
424 user = util.shortuser(user)
425 return user
425 return user
426
426
427 def expandpath(self, loc, default=None):
427 def expandpath(self, loc, default=None):
428 """Return repository location relative to cwd or from [paths]"""
428 """Return repository location relative to cwd or from [paths]"""
429 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
429 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
430 return loc
430 return loc
431
431
432 path = self.config('paths', loc)
432 path = self.config('paths', loc)
433 if not path and default is not None:
433 if not path and default is not None:
434 path = self.config('paths', default)
434 path = self.config('paths', default)
435 return path or loc
435 return path or loc
436
436
437 def pushbuffer(self):
437 def pushbuffer(self):
438 self._buffers.append([])
438 self._buffers.append([])
439
439
440 def popbuffer(self, labeled=False):
440 def popbuffer(self, labeled=False):
441 '''pop the last buffer and return the buffered output
441 '''pop the last buffer and return the buffered output
442
442
443 If labeled is True, any labels associated with buffered
443 If labeled is True, any labels associated with buffered
444 output will be handled. By default, this has no effect
444 output will be handled. By default, this has no effect
445 on the output returned, but extensions and GUI tools may
445 on the output returned, but extensions and GUI tools may
446 handle this argument and returned styled output. If output
446 handle this argument and returned styled output. If output
447 is being buffered so it can be captured and parsed or
447 is being buffered so it can be captured and parsed or
448 processed, labeled should not be set to True.
448 processed, labeled should not be set to True.
449 '''
449 '''
450 return "".join(self._buffers.pop())
450 return "".join(self._buffers.pop())
451
451
452 def write(self, *args, **opts):
452 def write(self, *args, **opts):
453 '''write args to output
453 '''write args to output
454
454
455 By default, this method simply writes to the buffer or stdout,
455 By default, this method simply writes to the buffer or stdout,
456 but extensions or GUI tools may override this method,
456 but extensions or GUI tools may override this method,
457 write_err(), popbuffer(), and label() to style output from
457 write_err(), popbuffer(), and label() to style output from
458 various parts of hg.
458 various parts of hg.
459
459
460 An optional keyword argument, "label", can be passed in.
460 An optional keyword argument, "label", can be passed in.
461 This should be a string containing label names separated by
461 This should be a string containing label names separated by
462 space. Label names take the form of "topic.type". For example,
462 space. Label names take the form of "topic.type". For example,
463 ui.debug() issues a label of "ui.debug".
463 ui.debug() issues a label of "ui.debug".
464
464
465 When labeling output for a specific command, a label of
465 When labeling output for a specific command, a label of
466 "cmdname.type" is recommended. For example, status issues
466 "cmdname.type" is recommended. For example, status issues
467 a label of "status.modified" for modified files.
467 a label of "status.modified" for modified files.
468 '''
468 '''
469 if self._buffers:
469 if self._buffers:
470 self._buffers[-1].extend([str(a) for a in args])
470 self._buffers[-1].extend([str(a) for a in args])
471 else:
471 else:
472 for a in args:
472 for a in args:
473 self.fout.write(str(a))
473 self.fout.write(str(a))
474
474
475 def write_err(self, *args, **opts):
475 def write_err(self, *args, **opts):
476 try:
476 try:
477 if not getattr(self.fout, 'closed', False):
477 if not getattr(self.fout, 'closed', False):
478 self.fout.flush()
478 self.fout.flush()
479 for a in args:
479 for a in args:
480 self.ferr.write(str(a))
480 self.ferr.write(str(a))
481 # stderr may be buffered under win32 when redirected to files,
481 # stderr may be buffered under win32 when redirected to files,
482 # including stdout.
482 # including stdout.
483 if not getattr(self.ferr, 'closed', False):
483 if not getattr(self.ferr, 'closed', False):
484 self.ferr.flush()
484 self.ferr.flush()
485 except IOError, inst:
485 except IOError, inst:
486 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
486 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
487 raise
487 raise
488
488
489 def flush(self):
489 def flush(self):
490 try: self.fout.flush()
490 try: self.fout.flush()
491 except (IOError, ValueError): pass
491 except (IOError, ValueError): pass
492 try: self.ferr.flush()
492 try: self.ferr.flush()
493 except (IOError, ValueError): pass
493 except (IOError, ValueError): pass
494
494
495 def _isatty(self, fh):
495 def _isatty(self, fh):
496 if self.configbool('ui', 'nontty', False):
496 if self.configbool('ui', 'nontty', False):
497 return False
497 return False
498 return util.isatty(fh)
498 return util.isatty(fh)
499
499
500 def interactive(self):
500 def interactive(self):
501 '''is interactive input allowed?
501 '''is interactive input allowed?
502
502
503 An interactive session is a session where input can be reasonably read
503 An interactive session is a session where input can be reasonably read
504 from `sys.stdin'. If this function returns false, any attempt to read
504 from `sys.stdin'. If this function returns false, any attempt to read
505 from stdin should fail with an error, unless a sensible default has been
505 from stdin should fail with an error, unless a sensible default has been
506 specified.
506 specified.
507
507
508 Interactiveness is triggered by the value of the `ui.interactive'
508 Interactiveness is triggered by the value of the `ui.interactive'
509 configuration variable or - if it is unset - when `sys.stdin' points
509 configuration variable or - if it is unset - when `sys.stdin' points
510 to a terminal device.
510 to a terminal device.
511
511
512 This function refers to input only; for output, see `ui.formatted()'.
512 This function refers to input only; for output, see `ui.formatted()'.
513 '''
513 '''
514 i = self.configbool("ui", "interactive", None)
514 i = self.configbool("ui", "interactive", None)
515 if i is None:
515 if i is None:
516 # some environments replace stdin without implementing isatty
516 # some environments replace stdin without implementing isatty
517 # usually those are non-interactive
517 # usually those are non-interactive
518 return self._isatty(self.fin)
518 return self._isatty(self.fin)
519
519
520 return i
520 return i
521
521
522 def termwidth(self):
522 def termwidth(self):
523 '''how wide is the terminal in columns?
523 '''how wide is the terminal in columns?
524 '''
524 '''
525 if 'COLUMNS' in os.environ:
525 if 'COLUMNS' in os.environ:
526 try:
526 try:
527 return int(os.environ['COLUMNS'])
527 return int(os.environ['COLUMNS'])
528 except ValueError:
528 except ValueError:
529 pass
529 pass
530 return util.termwidth()
530 return util.termwidth()
531
531
532 def formatted(self):
532 def formatted(self):
533 '''should formatted output be used?
533 '''should formatted output be used?
534
534
535 It is often desirable to format the output to suite the output medium.
535 It is often desirable to format the output to suite the output medium.
536 Examples of this are truncating long lines or colorizing messages.
536 Examples of this are truncating long lines or colorizing messages.
537 However, this is not often not desirable when piping output into other
537 However, this is not often not desirable when piping output into other
538 utilities, e.g. `grep'.
538 utilities, e.g. `grep'.
539
539
540 Formatted output is triggered by the value of the `ui.formatted'
540 Formatted output is triggered by the value of the `ui.formatted'
541 configuration variable or - if it is unset - when `sys.stdout' points
541 configuration variable or - if it is unset - when `sys.stdout' points
542 to a terminal device. Please note that `ui.formatted' should be
542 to a terminal device. Please note that `ui.formatted' should be
543 considered an implementation detail; it is not intended for use outside
543 considered an implementation detail; it is not intended for use outside
544 Mercurial or its extensions.
544 Mercurial or its extensions.
545
545
546 This function refers to output only; for input, see `ui.interactive()'.
546 This function refers to output only; for input, see `ui.interactive()'.
547 This function always returns false when in plain mode, see `ui.plain()'.
547 This function always returns false when in plain mode, see `ui.plain()'.
548 '''
548 '''
549 if self.plain():
549 if self.plain():
550 return False
550 return False
551
551
552 i = self.configbool("ui", "formatted", None)
552 i = self.configbool("ui", "formatted", None)
553 if i is None:
553 if i is None:
554 # some environments replace stdout without implementing isatty
554 # some environments replace stdout without implementing isatty
555 # usually those are non-interactive
555 # usually those are non-interactive
556 return self._isatty(self.fout)
556 return self._isatty(self.fout)
557
557
558 return i
558 return i
559
559
560 def _readline(self, prompt=''):
560 def _readline(self, prompt=''):
561 if self._isatty(self.fin):
561 if self._isatty(self.fin):
562 try:
562 try:
563 # magically add command line editing support, where
563 # magically add command line editing support, where
564 # available
564 # available
565 import readline
565 import readline
566 # force demandimport to really load the module
566 # force demandimport to really load the module
567 readline.read_history_file
567 readline.read_history_file
568 # windows sometimes raises something other than ImportError
568 # windows sometimes raises something other than ImportError
569 except Exception:
569 except Exception:
570 pass
570 pass
571
571
572 # call write() so output goes through subclassed implementation
572 # call write() so output goes through subclassed implementation
573 # e.g. color extension on Windows
573 # e.g. color extension on Windows
574 self.write(prompt)
574 self.write(prompt)
575
575
576 # instead of trying to emulate raw_input, swap (self.fin,
576 # instead of trying to emulate raw_input, swap (self.fin,
577 # self.fout) with (sys.stdin, sys.stdout)
577 # self.fout) with (sys.stdin, sys.stdout)
578 oldin = sys.stdin
578 oldin = sys.stdin
579 oldout = sys.stdout
579 oldout = sys.stdout
580 sys.stdin = self.fin
580 sys.stdin = self.fin
581 sys.stdout = self.fout
581 sys.stdout = self.fout
582 line = raw_input(' ')
582 line = raw_input(' ')
583 sys.stdin = oldin
583 sys.stdin = oldin
584 sys.stdout = oldout
584 sys.stdout = oldout
585
585
586 # When stdin is in binary mode on Windows, it can cause
586 # When stdin is in binary mode on Windows, it can cause
587 # raw_input() to emit an extra trailing carriage return
587 # raw_input() to emit an extra trailing carriage return
588 if os.linesep == '\r\n' and line and line[-1] == '\r':
588 if os.linesep == '\r\n' and line and line[-1] == '\r':
589 line = line[:-1]
589 line = line[:-1]
590 return line
590 return line
591
591
592 def prompt(self, msg, default="y"):
592 def prompt(self, msg, default="y"):
593 """Prompt user with msg, read response.
593 """Prompt user with msg, read response.
594 If ui is not interactive, the default is returned.
594 If ui is not interactive, the default is returned.
595 """
595 """
596 if not self.interactive():
596 if not self.interactive():
597 self.write(msg, ' ', default, "\n")
597 self.write(msg, ' ', default, "\n")
598 return default
598 return default
599 try:
599 try:
600 r = self._readline(self.label(msg, 'ui.prompt'))
600 r = self._readline(self.label(msg, 'ui.prompt'))
601 if not r:
601 if not r:
602 return default
602 return default
603 return r
603 return r
604 except EOFError:
604 except EOFError:
605 raise util.Abort(_('response expected'))
605 raise util.Abort(_('response expected'))
606
606
607 def promptchoice(self, msg, choices, default=0):
607 def promptchoice(self, msg, choices, default=0):
608 """Prompt user with msg, read response, and ensure it matches
608 """Prompt user with msg, read response, and ensure it matches
609 one of the provided choices. The index of the choice is returned.
609 one of the provided choices. The index of the choice is returned.
610 choices is a sequence of acceptable responses with the format:
610 choices is a sequence of acceptable responses with the format:
611 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
611 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
612 If ui is not interactive, the default is returned.
612 If ui is not interactive, the default is returned.
613 """
613 """
614 resps = [s[s.index('&')+1].lower() for s in choices]
614 resps = [s[s.index('&')+1].lower() for s in choices]
615 while True:
615 while True:
616 r = self.prompt(msg, resps[default])
616 r = self.prompt(msg, resps[default])
617 if r.lower() in resps:
617 if r.lower() in resps:
618 return resps.index(r.lower())
618 return resps.index(r.lower())
619 self.write(_("unrecognized response\n"))
619 self.write(_("unrecognized response\n"))
620
620
621 def getpass(self, prompt=None, default=None):
621 def getpass(self, prompt=None, default=None):
622 if not self.interactive():
622 if not self.interactive():
623 return default
623 return default
624 try:
624 try:
625 return getpass.getpass(prompt or _('password: '))
625 return getpass.getpass(prompt or _('password: '))
626 except EOFError:
626 except EOFError:
627 raise util.Abort(_('response expected'))
627 raise util.Abort(_('response expected'))
628 def status(self, *msg, **opts):
628 def status(self, *msg, **opts):
629 '''write status message to output (if ui.quiet is False)
629 '''write status message to output (if ui.quiet is False)
630
630
631 This adds an output label of "ui.status".
631 This adds an output label of "ui.status".
632 '''
632 '''
633 if not self.quiet:
633 if not self.quiet:
634 opts['label'] = opts.get('label', '') + ' ui.status'
634 opts['label'] = opts.get('label', '') + ' ui.status'
635 self.write(*msg, **opts)
635 self.write(*msg, **opts)
636 def warn(self, *msg, **opts):
636 def warn(self, *msg, **opts):
637 '''write warning message to output (stderr)
637 '''write warning message to output (stderr)
638
638
639 This adds an output label of "ui.warning".
639 This adds an output label of "ui.warning".
640 '''
640 '''
641 opts['label'] = opts.get('label', '') + ' ui.warning'
641 opts['label'] = opts.get('label', '') + ' ui.warning'
642 self.write_err(*msg, **opts)
642 self.write_err(*msg, **opts)
643 def note(self, *msg, **opts):
643 def note(self, *msg, **opts):
644 '''write note to output (if ui.verbose is True)
644 '''write note to output (if ui.verbose is True)
645
645
646 This adds an output label of "ui.note".
646 This adds an output label of "ui.note".
647 '''
647 '''
648 if self.verbose:
648 if self.verbose:
649 opts['label'] = opts.get('label', '') + ' ui.note'
649 opts['label'] = opts.get('label', '') + ' ui.note'
650 self.write(*msg, **opts)
650 self.write(*msg, **opts)
651 def debug(self, *msg, **opts):
651 def debug(self, *msg, **opts):
652 '''write debug message to output (if ui.debugflag is True)
652 '''write debug message to output (if ui.debugflag is True)
653
653
654 This adds an output label of "ui.debug".
654 This adds an output label of "ui.debug".
655 '''
655 '''
656 if self.debugflag:
656 if self.debugflag:
657 opts['label'] = opts.get('label', '') + ' ui.debug'
657 opts['label'] = opts.get('label', '') + ' ui.debug'
658 self.write(*msg, **opts)
658 self.write(*msg, **opts)
659 def edit(self, text, user):
659 def edit(self, text, user):
660 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
660 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
661 text=True)
661 text=True)
662 try:
662 try:
663 f = os.fdopen(fd, "w")
663 f = os.fdopen(fd, "w")
664 f.write(text)
664 f.write(text)
665 f.close()
665 f.close()
666
666
667 editor = self.geteditor()
667 editor = self.geteditor()
668
668
669 util.system("%s \"%s\"" % (editor, name),
669 util.system("%s \"%s\"" % (editor, name),
670 environ={'HGUSER': user},
670 environ={'HGUSER': user},
671 onerr=util.Abort, errprefix=_("edit failed"),
671 onerr=util.Abort, errprefix=_("edit failed"),
672 out=self.fout)
672 out=self.fout)
673
673
674 f = open(name)
674 f = open(name)
675 t = f.read()
675 t = f.read()
676 f.close()
676 f.close()
677 finally:
677 finally:
678 os.unlink(name)
678 os.unlink(name)
679
679
680 return t
680 return t
681
681
682 def traceback(self, exc=None):
682 def traceback(self, exc=None):
683 '''print exception traceback if traceback printing enabled.
683 '''print exception traceback if traceback printing enabled.
684 only to call in exception handler. returns true if traceback
684 only to call in exception handler. returns true if traceback
685 printed.'''
685 printed.'''
686 if self.tracebackflag:
686 if self.tracebackflag:
687 if exc:
687 if exc:
688 traceback.print_exception(exc[0], exc[1], exc[2],
688 traceback.print_exception(exc[0], exc[1], exc[2],
689 file=self.ferr)
689 file=self.ferr)
690 else:
690 else:
691 traceback.print_exc(file=self.ferr)
691 traceback.print_exc(file=self.ferr)
692 return self.tracebackflag
692 return self.tracebackflag
693
693
694 def geteditor(self):
694 def geteditor(self):
695 '''return editor to use'''
695 '''return editor to use'''
696 if sys.platform == 'plan9':
696 if sys.platform == 'plan9':
697 # vi is the MIPS instruction simulator on Plan 9. We
697 # vi is the MIPS instruction simulator on Plan 9. We
698 # instead default to E to plumb commit messages to
698 # instead default to E to plumb commit messages to
699 # avoid confusion.
699 # avoid confusion.
700 editor = 'E'
700 editor = 'E'
701 else:
701 else:
702 editor = 'vi'
702 editor = 'vi'
703 return (os.environ.get("HGEDITOR") or
703 return (os.environ.get("HGEDITOR") or
704 self.config("ui", "editor") or
704 self.config("ui", "editor") or
705 os.environ.get("VISUAL") or
705 os.environ.get("VISUAL") or
706 os.environ.get("EDITOR", editor))
706 os.environ.get("EDITOR", editor))
707
707
708 def progress(self, topic, pos, item="", unit="", total=None):
708 def progress(self, topic, pos, item="", unit="", total=None):
709 '''show a progress message
709 '''show a progress message
710
710
711 With stock hg, this is simply a debug message that is hidden
711 With stock hg, this is simply a debug message that is hidden
712 by default, but with extensions or GUI tools it may be
712 by default, but with extensions or GUI tools it may be
713 visible. 'topic' is the current operation, 'item' is a
713 visible. 'topic' is the current operation, 'item' is a
714 non-numeric marker of the current position (ie the currently
714 non-numeric marker of the current position (ie the currently
715 in-process file), 'pos' is the current numeric position (ie
715 in-process file), 'pos' is the current numeric position (ie
716 revision, bytes, etc.), unit is a corresponding unit label,
716 revision, bytes, etc.), unit is a corresponding unit label,
717 and total is the highest expected pos.
717 and total is the highest expected pos.
718
718
719 Multiple nested topics may be active at a time.
719 Multiple nested topics may be active at a time.
720
720
721 All topics should be marked closed by setting pos to None at
721 All topics should be marked closed by setting pos to None at
722 termination.
722 termination.
723 '''
723 '''
724
724
725 if pos is None or not self.debugflag:
725 if pos is None or not self.debugflag:
726 return
726 return
727
727
728 if unit:
728 if unit:
729 unit = ' ' + unit
729 unit = ' ' + unit
730 if item:
730 if item:
731 item = ' ' + item
731 item = ' ' + item
732
732
733 if total:
733 if total:
734 pct = 100.0 * pos / total
734 pct = 100.0 * pos / total
735 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
735 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
736 % (topic, item, pos, total, unit, pct))
736 % (topic, item, pos, total, unit, pct))
737 else:
737 else:
738 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
738 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
739
739
740 def log(self, service, message):
740 def log(self, service, message):
741 '''hook for logging facility extensions
741 '''hook for logging facility extensions
742
742
743 service should be a readily-identifiable subsystem, which will
743 service should be a readily-identifiable subsystem, which will
744 allow filtering.
744 allow filtering.
745 message should be a newline-terminated string to log.
745 message should be a newline-terminated string to log.
746 '''
746 '''
747 pass
747 pass
748
748
749 def label(self, msg, label):
749 def label(self, msg, label):
750 '''style msg based on supplied label
750 '''style msg based on supplied label
751
751
752 Like ui.write(), this just returns msg unchanged, but extensions
752 Like ui.write(), this just returns msg unchanged, but extensions
753 and GUI tools can override it to allow styling output without
753 and GUI tools can override it to allow styling output without
754 writing it.
754 writing it.
755
755
756 ui.write(s, 'label') is equivalent to
756 ui.write(s, 'label') is equivalent to
757 ui.write(ui.label(s, 'label')).
757 ui.write(ui.label(s, 'label')).
758 '''
758 '''
759 return msg
759 return msg
@@ -1,179 +1,179
1 # same user, same group
1 # same user, same group
2 trusted
2 trusted
3 global = /some/path
3 global = /some/path
4 local = /another/path
4 local = /another/path
5 untrusted
5 untrusted
6 . . global = /some/path
6 . . global = /some/path
7 . . local = /another/path
7 . . local = /another/path
8
8
9 # same user, different group
9 # same user, different group
10 trusted
10 trusted
11 global = /some/path
11 global = /some/path
12 local = /another/path
12 local = /another/path
13 untrusted
13 untrusted
14 . . global = /some/path
14 . . global = /some/path
15 . . local = /another/path
15 . . local = /another/path
16
16
17 # different user, same group
17 # different user, same group
18 Not trusting file .hg/hgrc from untrusted user abc, group bar
18 not trusting file .hg/hgrc from untrusted user abc, group bar
19 trusted
19 trusted
20 global = /some/path
20 global = /some/path
21 untrusted
21 untrusted
22 . . global = /some/path
22 . . global = /some/path
23 . . local = /another/path
23 . . local = /another/path
24
24
25 # different user, same group, but we trust the group
25 # different user, same group, but we trust the group
26 trusted
26 trusted
27 global = /some/path
27 global = /some/path
28 local = /another/path
28 local = /another/path
29 untrusted
29 untrusted
30 . . global = /some/path
30 . . global = /some/path
31 . . local = /another/path
31 . . local = /another/path
32
32
33 # different user, different group
33 # different user, different group
34 Not trusting file .hg/hgrc from untrusted user abc, group def
34 not trusting file .hg/hgrc from untrusted user abc, group def
35 trusted
35 trusted
36 global = /some/path
36 global = /some/path
37 untrusted
37 untrusted
38 . . global = /some/path
38 . . global = /some/path
39 . . local = /another/path
39 . . local = /another/path
40
40
41 # different user, different group, but we trust the user
41 # different user, different group, but we trust the user
42 trusted
42 trusted
43 global = /some/path
43 global = /some/path
44 local = /another/path
44 local = /another/path
45 untrusted
45 untrusted
46 . . global = /some/path
46 . . global = /some/path
47 . . local = /another/path
47 . . local = /another/path
48
48
49 # different user, different group, but we trust the group
49 # different user, different group, but we trust the group
50 trusted
50 trusted
51 global = /some/path
51 global = /some/path
52 local = /another/path
52 local = /another/path
53 untrusted
53 untrusted
54 . . global = /some/path
54 . . global = /some/path
55 . . local = /another/path
55 . . local = /another/path
56
56
57 # 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
58 trusted
58 trusted
59 global = /some/path
59 global = /some/path
60 local = /another/path
60 local = /another/path
61 untrusted
61 untrusted
62 . . global = /some/path
62 . . global = /some/path
63 . . local = /another/path
63 . . local = /another/path
64
64
65 # we trust all users
65 # we trust all users
66 # different user, different group
66 # different user, different group
67 trusted
67 trusted
68 global = /some/path
68 global = /some/path
69 local = /another/path
69 local = /another/path
70 untrusted
70 untrusted
71 . . global = /some/path
71 . . global = /some/path
72 . . local = /another/path
72 . . local = /another/path
73
73
74 # we trust all groups
74 # we trust all groups
75 # different user, different group
75 # different user, different group
76 trusted
76 trusted
77 global = /some/path
77 global = /some/path
78 local = /another/path
78 local = /another/path
79 untrusted
79 untrusted
80 . . global = /some/path
80 . . global = /some/path
81 . . local = /another/path
81 . . local = /another/path
82
82
83 # we trust all users and groups
83 # we trust all users and groups
84 # different user, different group
84 # different user, different group
85 trusted
85 trusted
86 global = /some/path
86 global = /some/path
87 local = /another/path
87 local = /another/path
88 untrusted
88 untrusted
89 . . global = /some/path
89 . . global = /some/path
90 . . local = /another/path
90 . . local = /another/path
91
91
92 # 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
93 # different user, different group
93 # different user, different group
94 Not trusting file .hg/hgrc from untrusted user abc, group def
94 not trusting file .hg/hgrc from untrusted user abc, group def
95 trusted
95 trusted
96 global = /some/path
96 global = /some/path
97 untrusted
97 untrusted
98 . . global = /some/path
98 . . global = /some/path
99 . . local = /another/path
99 . . local = /another/path
100
100
101 # list of user names
101 # list of user names
102 # different user, different group, but we trust the user
102 # different user, different group, but we trust the user
103 trusted
103 trusted
104 global = /some/path
104 global = /some/path
105 local = /another/path
105 local = /another/path
106 untrusted
106 untrusted
107 . . global = /some/path
107 . . global = /some/path
108 . . local = /another/path
108 . . local = /another/path
109
109
110 # list of group names
110 # list of group names
111 # different user, different group, but we trust the group
111 # different user, different group, but we trust the group
112 trusted
112 trusted
113 global = /some/path
113 global = /some/path
114 local = /another/path
114 local = /another/path
115 untrusted
115 untrusted
116 . . global = /some/path
116 . . global = /some/path
117 . . local = /another/path
117 . . local = /another/path
118
118
119 # 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
120 # different user, different group
120 # different user, different group
121 Not trusting file .hg/hgrc from untrusted user abc, group def
121 not trusting file .hg/hgrc from untrusted user abc, group def
122 trusted
122 trusted
123 global = /some/path
123 global = /some/path
124 untrusted
124 untrusted
125 . . global = /some/path
125 . . global = /some/path
126 . . local = /another/path
126 . . local = /another/path
127
127
128 # prints debug warnings
128 # prints debug warnings
129 # different user, different group
129 # different user, different group
130 Not trusting file .hg/hgrc from untrusted user abc, group def
130 not trusting file .hg/hgrc from untrusted user abc, group def
131 trusted
131 trusted
132 ignoring untrusted configuration option paths.local = /another/path
132 ignoring untrusted configuration option paths.local = /another/path
133 global = /some/path
133 global = /some/path
134 untrusted
134 untrusted
135 . . global = /some/path
135 . . global = /some/path
136 .ignoring untrusted configuration option paths.local = /another/path
136 .ignoring untrusted configuration option paths.local = /another/path
137 . local = /another/path
137 . local = /another/path
138
138
139 # report_untrusted enabled without debug hides warnings
139 # report_untrusted enabled without debug hides warnings
140 # different user, different group
140 # different user, different group
141 trusted
141 trusted
142 global = /some/path
142 global = /some/path
143 untrusted
143 untrusted
144 . . global = /some/path
144 . . global = /some/path
145 . . local = /another/path
145 . . local = /another/path
146
146
147 # report_untrusted enabled with debug shows warnings
147 # report_untrusted enabled with debug shows warnings
148 # different user, different group
148 # different user, different group
149 Not trusting file .hg/hgrc from untrusted user abc, group def
149 not trusting file .hg/hgrc from untrusted user abc, group def
150 trusted
150 trusted
151 ignoring untrusted configuration option paths.local = /another/path
151 ignoring untrusted configuration option paths.local = /another/path
152 global = /some/path
152 global = /some/path
153 untrusted
153 untrusted
154 . . global = /some/path
154 . . global = /some/path
155 .ignoring untrusted configuration option paths.local = /another/path
155 .ignoring untrusted configuration option paths.local = /another/path
156 . local = /another/path
156 . local = /another/path
157
157
158 # ui.readconfig sections
158 # ui.readconfig sections
159 quux
159 quux
160
160
161 # read trusted, untrusted, new ui, trusted
161 # read trusted, untrusted, new ui, trusted
162 Not trusting file foobar from untrusted user abc, group def
162 not trusting file foobar from untrusted user abc, group def
163 trusted:
163 trusted:
164 ignoring untrusted configuration option foobar.baz = quux
164 ignoring untrusted configuration option foobar.baz = quux
165 None
165 None
166 untrusted:
166 untrusted:
167 quux
167 quux
168
168
169 # error handling
169 # error handling
170 # file doesn't exist
170 # file doesn't exist
171 # same user, same group
171 # same user, same group
172 # different user, different group
172 # different user, different group
173
173
174 # parse error
174 # parse error
175 # different user, different group
175 # different user, different group
176 Not trusting file .hg/hgrc from untrusted user abc, group def
176 not trusting file .hg/hgrc from untrusted user abc, group def
177 ('foo', '.hg/hgrc:1')
177 ('foo', '.hg/hgrc:1')
178 # same user, same group
178 # same user, same group
179 ('foo', '.hg/hgrc:1')
179 ('foo', '.hg/hgrc:1')
General Comments 0
You need to be logged in to leave comments. Login now