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