##// END OF EJS Templates
ui: ignore ui.logtemplate and ui.style when HGPLAIN is set...
Yuya Nishihara -
r10567:99272344 stable
parent child Browse files
Show More
@@ -1,418 +1,419 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, util, error
10 import config, util, error
11
11
12 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True,
12 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True,
13 '0': False, 'no': False, 'false': False, 'off': False}
13 '0': False, 'no': False, 'false': False, 'off': False}
14
14
15 class ui(object):
15 class ui(object):
16 def __init__(self, src=None):
16 def __init__(self, src=None):
17 self._buffers = []
17 self._buffers = []
18 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
18 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
19 self._reportuntrusted = True
19 self._reportuntrusted = True
20 self._ocfg = config.config() # overlay
20 self._ocfg = config.config() # overlay
21 self._tcfg = config.config() # trusted
21 self._tcfg = config.config() # trusted
22 self._ucfg = config.config() # untrusted
22 self._ucfg = config.config() # untrusted
23 self._trustusers = set()
23 self._trustusers = set()
24 self._trustgroups = set()
24 self._trustgroups = set()
25
25
26 if src:
26 if src:
27 self._tcfg = src._tcfg.copy()
27 self._tcfg = src._tcfg.copy()
28 self._ucfg = src._ucfg.copy()
28 self._ucfg = src._ucfg.copy()
29 self._ocfg = src._ocfg.copy()
29 self._ocfg = src._ocfg.copy()
30 self._trustusers = src._trustusers.copy()
30 self._trustusers = src._trustusers.copy()
31 self._trustgroups = src._trustgroups.copy()
31 self._trustgroups = src._trustgroups.copy()
32 self.environ = src.environ
32 self.environ = src.environ
33 self.fixconfig()
33 self.fixconfig()
34 else:
34 else:
35 # shared read-only environment
35 # shared read-only environment
36 self.environ = os.environ
36 self.environ = os.environ
37 # we always trust global config files
37 # we always trust global config files
38 for f in util.rcpath():
38 for f in util.rcpath():
39 self.readconfig(f, trust=True)
39 self.readconfig(f, trust=True)
40
40
41 def copy(self):
41 def copy(self):
42 return self.__class__(self)
42 return self.__class__(self)
43
43
44 def _is_trusted(self, fp, f):
44 def _is_trusted(self, fp, f):
45 st = util.fstat(fp)
45 st = util.fstat(fp)
46 if util.isowner(st):
46 if util.isowner(st):
47 return True
47 return True
48
48
49 tusers, tgroups = self._trustusers, self._trustgroups
49 tusers, tgroups = self._trustusers, self._trustgroups
50 if '*' in tusers or '*' in tgroups:
50 if '*' in tusers or '*' in tgroups:
51 return True
51 return True
52
52
53 user = util.username(st.st_uid)
53 user = util.username(st.st_uid)
54 group = util.groupname(st.st_gid)
54 group = util.groupname(st.st_gid)
55 if user in tusers or group in tgroups or user == util.username():
55 if user in tusers or group in tgroups or user == util.username():
56 return True
56 return True
57
57
58 if self._reportuntrusted:
58 if self._reportuntrusted:
59 self.warn(_('Not trusting file %s from untrusted '
59 self.warn(_('Not trusting file %s from untrusted '
60 'user %s, group %s\n') % (f, user, group))
60 'user %s, group %s\n') % (f, user, group))
61 return False
61 return False
62
62
63 def readconfig(self, filename, root=None, trust=False,
63 def readconfig(self, filename, root=None, trust=False,
64 sections=None, remap=None):
64 sections=None, remap=None):
65 try:
65 try:
66 fp = open(filename)
66 fp = open(filename)
67 except IOError:
67 except IOError:
68 if not sections: # ignore unless we were looking for something
68 if not sections: # ignore unless we were looking for something
69 return
69 return
70 raise
70 raise
71
71
72 cfg = config.config()
72 cfg = config.config()
73 trusted = sections or trust or self._is_trusted(fp, filename)
73 trusted = sections or trust or self._is_trusted(fp, filename)
74
74
75 try:
75 try:
76 cfg.read(filename, fp, sections=sections, remap=remap)
76 cfg.read(filename, fp, sections=sections, remap=remap)
77 except error.ConfigError, inst:
77 except error.ConfigError, inst:
78 if trusted:
78 if trusted:
79 raise
79 raise
80 self.warn(_("Ignored: %s\n") % str(inst))
80 self.warn(_("Ignored: %s\n") % str(inst))
81
81
82 if self.plain():
82 if self.plain():
83 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
83 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
84 'logtemplate', 'style',
84 'traceback', 'verbose'):
85 'traceback', 'verbose'):
85 if k in cfg['ui']:
86 if k in cfg['ui']:
86 del cfg['ui'][k]
87 del cfg['ui'][k]
87 for k, v in cfg.items('alias'):
88 for k, v in cfg.items('alias'):
88 del cfg['alias'][k]
89 del cfg['alias'][k]
89 for k, v in cfg.items('defaults'):
90 for k, v in cfg.items('defaults'):
90 del cfg['defaults'][k]
91 del cfg['defaults'][k]
91
92
92 if trusted:
93 if trusted:
93 self._tcfg.update(cfg)
94 self._tcfg.update(cfg)
94 self._tcfg.update(self._ocfg)
95 self._tcfg.update(self._ocfg)
95 self._ucfg.update(cfg)
96 self._ucfg.update(cfg)
96 self._ucfg.update(self._ocfg)
97 self._ucfg.update(self._ocfg)
97
98
98 if root is None:
99 if root is None:
99 root = os.path.expanduser('~')
100 root = os.path.expanduser('~')
100 self.fixconfig(root=root)
101 self.fixconfig(root=root)
101
102
102 def fixconfig(self, root=None):
103 def fixconfig(self, root=None):
103 # translate paths relative to root (or home) into absolute paths
104 # translate paths relative to root (or home) into absolute paths
104 root = root or os.getcwd()
105 root = root or os.getcwd()
105 for c in self._tcfg, self._ucfg, self._ocfg:
106 for c in self._tcfg, self._ucfg, self._ocfg:
106 for n, p in c.items('paths'):
107 for n, p in c.items('paths'):
107 if p and "://" not in p and not os.path.isabs(p):
108 if p and "://" not in p and not os.path.isabs(p):
108 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
109 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
109
110
110 # update ui options
111 # update ui options
111 self.debugflag = self.configbool('ui', 'debug')
112 self.debugflag = self.configbool('ui', 'debug')
112 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
113 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
113 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
114 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
114 if self.verbose and self.quiet:
115 if self.verbose and self.quiet:
115 self.quiet = self.verbose = False
116 self.quiet = self.verbose = False
116 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
117 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
117 self.tracebackflag = self.configbool('ui', 'traceback', False)
118 self.tracebackflag = self.configbool('ui', 'traceback', False)
118
119
119 # update trust information
120 # update trust information
120 self._trustusers.update(self.configlist('trusted', 'users'))
121 self._trustusers.update(self.configlist('trusted', 'users'))
121 self._trustgroups.update(self.configlist('trusted', 'groups'))
122 self._trustgroups.update(self.configlist('trusted', 'groups'))
122
123
123 def setconfig(self, section, name, value):
124 def setconfig(self, section, name, value):
124 for cfg in (self._ocfg, self._tcfg, self._ucfg):
125 for cfg in (self._ocfg, self._tcfg, self._ucfg):
125 cfg.set(section, name, value)
126 cfg.set(section, name, value)
126 self.fixconfig()
127 self.fixconfig()
127
128
128 def _data(self, untrusted):
129 def _data(self, untrusted):
129 return untrusted and self._ucfg or self._tcfg
130 return untrusted and self._ucfg or self._tcfg
130
131
131 def configsource(self, section, name, untrusted=False):
132 def configsource(self, section, name, untrusted=False):
132 return self._data(untrusted).source(section, name) or 'none'
133 return self._data(untrusted).source(section, name) or 'none'
133
134
134 def config(self, section, name, default=None, untrusted=False):
135 def config(self, section, name, default=None, untrusted=False):
135 value = self._data(untrusted).get(section, name, default)
136 value = self._data(untrusted).get(section, name, default)
136 if self.debugflag and not untrusted and self._reportuntrusted:
137 if self.debugflag and not untrusted and self._reportuntrusted:
137 uvalue = self._ucfg.get(section, name)
138 uvalue = self._ucfg.get(section, name)
138 if uvalue is not None and uvalue != value:
139 if uvalue is not None and uvalue != value:
139 self.debug(_("ignoring untrusted configuration option "
140 self.debug(_("ignoring untrusted configuration option "
140 "%s.%s = %s\n") % (section, name, uvalue))
141 "%s.%s = %s\n") % (section, name, uvalue))
141 return value
142 return value
142
143
143 def configbool(self, section, name, default=False, untrusted=False):
144 def configbool(self, section, name, default=False, untrusted=False):
144 v = self.config(section, name, None, untrusted)
145 v = self.config(section, name, None, untrusted)
145 if v is None:
146 if v is None:
146 return default
147 return default
147 if isinstance(v, bool):
148 if isinstance(v, bool):
148 return v
149 return v
149 if v.lower() not in _booleans:
150 if v.lower() not in _booleans:
150 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
151 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
151 % (section, name, v))
152 % (section, name, v))
152 return _booleans[v.lower()]
153 return _booleans[v.lower()]
153
154
154 def configlist(self, section, name, default=None, untrusted=False):
155 def configlist(self, section, name, default=None, untrusted=False):
155 """Return a list of comma/space separated strings"""
156 """Return a list of comma/space separated strings"""
156 result = self.config(section, name, untrusted=untrusted)
157 result = self.config(section, name, untrusted=untrusted)
157 if result is None:
158 if result is None:
158 result = default or []
159 result = default or []
159 if isinstance(result, basestring):
160 if isinstance(result, basestring):
160 result = result.replace(",", " ").split()
161 result = result.replace(",", " ").split()
161 return result
162 return result
162
163
163 def has_section(self, section, untrusted=False):
164 def has_section(self, section, untrusted=False):
164 '''tell whether section exists in config.'''
165 '''tell whether section exists in config.'''
165 return section in self._data(untrusted)
166 return section in self._data(untrusted)
166
167
167 def configitems(self, section, untrusted=False):
168 def configitems(self, section, untrusted=False):
168 items = self._data(untrusted).items(section)
169 items = self._data(untrusted).items(section)
169 if self.debugflag and not untrusted and self._reportuntrusted:
170 if self.debugflag and not untrusted and self._reportuntrusted:
170 for k, v in self._ucfg.items(section):
171 for k, v in self._ucfg.items(section):
171 if self._tcfg.get(section, k) != v:
172 if self._tcfg.get(section, k) != v:
172 self.debug(_("ignoring untrusted configuration option "
173 self.debug(_("ignoring untrusted configuration option "
173 "%s.%s = %s\n") % (section, k, v))
174 "%s.%s = %s\n") % (section, k, v))
174 return items
175 return items
175
176
176 def walkconfig(self, untrusted=False):
177 def walkconfig(self, untrusted=False):
177 cfg = self._data(untrusted)
178 cfg = self._data(untrusted)
178 for section in cfg.sections():
179 for section in cfg.sections():
179 for name, value in self.configitems(section, untrusted):
180 for name, value in self.configitems(section, untrusted):
180 yield section, name, str(value).replace('\n', '\\n')
181 yield section, name, str(value).replace('\n', '\\n')
181
182
182 def plain(self):
183 def plain(self):
183 return 'HGPLAIN' in os.environ
184 return 'HGPLAIN' in os.environ
184
185
185 def username(self):
186 def username(self):
186 """Return default username to be used in commits.
187 """Return default username to be used in commits.
187
188
188 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
189 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
189 and stop searching if one of these is set.
190 and stop searching if one of these is set.
190 If not found and ui.askusername is True, ask the user, else use
191 If not found and ui.askusername is True, ask the user, else use
191 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
192 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
192 """
193 """
193 user = os.environ.get("HGUSER")
194 user = os.environ.get("HGUSER")
194 if user is None:
195 if user is None:
195 user = self.config("ui", "username")
196 user = self.config("ui", "username")
196 if user is None:
197 if user is None:
197 user = os.environ.get("EMAIL")
198 user = os.environ.get("EMAIL")
198 if user is None and self.configbool("ui", "askusername"):
199 if user is None and self.configbool("ui", "askusername"):
199 user = self.prompt(_("enter a commit username:"), default=None)
200 user = self.prompt(_("enter a commit username:"), default=None)
200 if user is None and not self.interactive():
201 if user is None and not self.interactive():
201 try:
202 try:
202 user = '%s@%s' % (util.getuser(), socket.getfqdn())
203 user = '%s@%s' % (util.getuser(), socket.getfqdn())
203 self.warn(_("No username found, using '%s' instead\n") % user)
204 self.warn(_("No username found, using '%s' instead\n") % user)
204 except KeyError:
205 except KeyError:
205 pass
206 pass
206 if not user:
207 if not user:
207 raise util.Abort(_('no username supplied (see "hg help config")'))
208 raise util.Abort(_('no username supplied (see "hg help config")'))
208 if "\n" in user:
209 if "\n" in user:
209 raise util.Abort(_("username %s contains a newline\n") % repr(user))
210 raise util.Abort(_("username %s contains a newline\n") % repr(user))
210 return user
211 return user
211
212
212 def shortuser(self, user):
213 def shortuser(self, user):
213 """Return a short representation of a user name or email address."""
214 """Return a short representation of a user name or email address."""
214 if not self.verbose:
215 if not self.verbose:
215 user = util.shortuser(user)
216 user = util.shortuser(user)
216 return user
217 return user
217
218
218 def _path(self, loc):
219 def _path(self, loc):
219 p = self.config('paths', loc)
220 p = self.config('paths', loc)
220 if p:
221 if p:
221 if '%%' in p:
222 if '%%' in p:
222 self.warn("(deprecated '%%' in path %s=%s from %s)\n" %
223 self.warn("(deprecated '%%' in path %s=%s from %s)\n" %
223 (loc, p, self.configsource('paths', loc)))
224 (loc, p, self.configsource('paths', loc)))
224 p = p.replace('%%', '%')
225 p = p.replace('%%', '%')
225 p = util.expandpath(p)
226 p = util.expandpath(p)
226 return p
227 return p
227
228
228 def expandpath(self, loc, default=None):
229 def expandpath(self, loc, default=None):
229 """Return repository location relative to cwd or from [paths]"""
230 """Return repository location relative to cwd or from [paths]"""
230 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
231 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
231 return loc
232 return loc
232
233
233 path = self._path(loc)
234 path = self._path(loc)
234 if not path and default is not None:
235 if not path and default is not None:
235 path = self._path(default)
236 path = self._path(default)
236 return path or loc
237 return path or loc
237
238
238 def pushbuffer(self):
239 def pushbuffer(self):
239 self._buffers.append([])
240 self._buffers.append([])
240
241
241 def popbuffer(self):
242 def popbuffer(self):
242 return "".join(self._buffers.pop())
243 return "".join(self._buffers.pop())
243
244
244 def write(self, *args):
245 def write(self, *args):
245 if self._buffers:
246 if self._buffers:
246 self._buffers[-1].extend([str(a) for a in args])
247 self._buffers[-1].extend([str(a) for a in args])
247 else:
248 else:
248 for a in args:
249 for a in args:
249 sys.stdout.write(str(a))
250 sys.stdout.write(str(a))
250
251
251 def write_err(self, *args):
252 def write_err(self, *args):
252 try:
253 try:
253 if not getattr(sys.stdout, 'closed', False):
254 if not getattr(sys.stdout, 'closed', False):
254 sys.stdout.flush()
255 sys.stdout.flush()
255 for a in args:
256 for a in args:
256 sys.stderr.write(str(a))
257 sys.stderr.write(str(a))
257 # stderr may be buffered under win32 when redirected to files,
258 # stderr may be buffered under win32 when redirected to files,
258 # including stdout.
259 # including stdout.
259 if not getattr(sys.stderr, 'closed', False):
260 if not getattr(sys.stderr, 'closed', False):
260 sys.stderr.flush()
261 sys.stderr.flush()
261 except IOError, inst:
262 except IOError, inst:
262 if inst.errno != errno.EPIPE:
263 if inst.errno != errno.EPIPE:
263 raise
264 raise
264
265
265 def flush(self):
266 def flush(self):
266 try: sys.stdout.flush()
267 try: sys.stdout.flush()
267 except: pass
268 except: pass
268 try: sys.stderr.flush()
269 try: sys.stderr.flush()
269 except: pass
270 except: pass
270
271
271 def interactive(self):
272 def interactive(self):
272 i = self.configbool("ui", "interactive", None)
273 i = self.configbool("ui", "interactive", None)
273 if i is None:
274 if i is None:
274 try:
275 try:
275 return sys.stdin.isatty()
276 return sys.stdin.isatty()
276 except AttributeError:
277 except AttributeError:
277 # some environments replace stdin without implementing isatty
278 # some environments replace stdin without implementing isatty
278 # usually those are non-interactive
279 # usually those are non-interactive
279 return False
280 return False
280
281
281 return i
282 return i
282
283
283 def _readline(self, prompt=''):
284 def _readline(self, prompt=''):
284 if sys.stdin.isatty():
285 if sys.stdin.isatty():
285 try:
286 try:
286 # magically add command line editing support, where
287 # magically add command line editing support, where
287 # available
288 # available
288 import readline
289 import readline
289 # force demandimport to really load the module
290 # force demandimport to really load the module
290 readline.read_history_file
291 readline.read_history_file
291 # windows sometimes raises something other than ImportError
292 # windows sometimes raises something other than ImportError
292 except Exception:
293 except Exception:
293 pass
294 pass
294 line = raw_input(prompt)
295 line = raw_input(prompt)
295 # When stdin is in binary mode on Windows, it can cause
296 # When stdin is in binary mode on Windows, it can cause
296 # raw_input() to emit an extra trailing carriage return
297 # raw_input() to emit an extra trailing carriage return
297 if os.linesep == '\r\n' and line and line[-1] == '\r':
298 if os.linesep == '\r\n' and line and line[-1] == '\r':
298 line = line[:-1]
299 line = line[:-1]
299 return line
300 return line
300
301
301 def prompt(self, msg, default="y"):
302 def prompt(self, msg, default="y"):
302 """Prompt user with msg, read response.
303 """Prompt user with msg, read response.
303 If ui is not interactive, the default is returned.
304 If ui is not interactive, the default is returned.
304 """
305 """
305 if not self.interactive():
306 if not self.interactive():
306 self.write(msg, ' ', default, "\n")
307 self.write(msg, ' ', default, "\n")
307 return default
308 return default
308 try:
309 try:
309 r = self._readline(msg + ' ')
310 r = self._readline(msg + ' ')
310 if not r:
311 if not r:
311 return default
312 return default
312 return r
313 return r
313 except EOFError:
314 except EOFError:
314 raise util.Abort(_('response expected'))
315 raise util.Abort(_('response expected'))
315
316
316 def promptchoice(self, msg, choices, default=0):
317 def promptchoice(self, msg, choices, default=0):
317 """Prompt user with msg, read response, and ensure it matches
318 """Prompt user with msg, read response, and ensure it matches
318 one of the provided choices. The index of the choice is returned.
319 one of the provided choices. The index of the choice is returned.
319 choices is a sequence of acceptable responses with the format:
320 choices is a sequence of acceptable responses with the format:
320 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
321 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
321 If ui is not interactive, the default is returned.
322 If ui is not interactive, the default is returned.
322 """
323 """
323 resps = [s[s.index('&')+1].lower() for s in choices]
324 resps = [s[s.index('&')+1].lower() for s in choices]
324 while True:
325 while True:
325 r = self.prompt(msg, resps[default])
326 r = self.prompt(msg, resps[default])
326 if r.lower() in resps:
327 if r.lower() in resps:
327 return resps.index(r.lower())
328 return resps.index(r.lower())
328 self.write(_("unrecognized response\n"))
329 self.write(_("unrecognized response\n"))
329
330
330 def getpass(self, prompt=None, default=None):
331 def getpass(self, prompt=None, default=None):
331 if not self.interactive():
332 if not self.interactive():
332 return default
333 return default
333 try:
334 try:
334 return getpass.getpass(prompt or _('password: '))
335 return getpass.getpass(prompt or _('password: '))
335 except EOFError:
336 except EOFError:
336 raise util.Abort(_('response expected'))
337 raise util.Abort(_('response expected'))
337 def status(self, *msg):
338 def status(self, *msg):
338 if not self.quiet:
339 if not self.quiet:
339 self.write(*msg)
340 self.write(*msg)
340 def warn(self, *msg):
341 def warn(self, *msg):
341 self.write_err(*msg)
342 self.write_err(*msg)
342 def note(self, *msg):
343 def note(self, *msg):
343 if self.verbose:
344 if self.verbose:
344 self.write(*msg)
345 self.write(*msg)
345 def debug(self, *msg):
346 def debug(self, *msg):
346 if self.debugflag:
347 if self.debugflag:
347 self.write(*msg)
348 self.write(*msg)
348 def edit(self, text, user):
349 def edit(self, text, user):
349 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
350 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
350 text=True)
351 text=True)
351 try:
352 try:
352 f = os.fdopen(fd, "w")
353 f = os.fdopen(fd, "w")
353 f.write(text)
354 f.write(text)
354 f.close()
355 f.close()
355
356
356 editor = self.geteditor()
357 editor = self.geteditor()
357
358
358 util.system("%s \"%s\"" % (editor, name),
359 util.system("%s \"%s\"" % (editor, name),
359 environ={'HGUSER': user},
360 environ={'HGUSER': user},
360 onerr=util.Abort, errprefix=_("edit failed"))
361 onerr=util.Abort, errprefix=_("edit failed"))
361
362
362 f = open(name)
363 f = open(name)
363 t = f.read()
364 t = f.read()
364 f.close()
365 f.close()
365 finally:
366 finally:
366 os.unlink(name)
367 os.unlink(name)
367
368
368 return t
369 return t
369
370
370 def traceback(self, exc=None):
371 def traceback(self, exc=None):
371 '''print exception traceback if traceback printing enabled.
372 '''print exception traceback if traceback printing enabled.
372 only to call in exception handler. returns true if traceback
373 only to call in exception handler. returns true if traceback
373 printed.'''
374 printed.'''
374 if self.tracebackflag:
375 if self.tracebackflag:
375 if exc:
376 if exc:
376 traceback.print_exception(exc[0], exc[1], exc[2])
377 traceback.print_exception(exc[0], exc[1], exc[2])
377 else:
378 else:
378 traceback.print_exc()
379 traceback.print_exc()
379 return self.tracebackflag
380 return self.tracebackflag
380
381
381 def geteditor(self):
382 def geteditor(self):
382 '''return editor to use'''
383 '''return editor to use'''
383 return (os.environ.get("HGEDITOR") or
384 return (os.environ.get("HGEDITOR") or
384 self.config("ui", "editor") or
385 self.config("ui", "editor") or
385 os.environ.get("VISUAL") or
386 os.environ.get("VISUAL") or
386 os.environ.get("EDITOR", "vi"))
387 os.environ.get("EDITOR", "vi"))
387
388
388 def progress(self, topic, pos, item="", unit="", total=None):
389 def progress(self, topic, pos, item="", unit="", total=None):
389 '''show a progress message
390 '''show a progress message
390
391
391 With stock hg, this is simply a debug message that is hidden
392 With stock hg, this is simply a debug message that is hidden
392 by default, but with extensions or GUI tools it may be
393 by default, but with extensions or GUI tools it may be
393 visible. 'topic' is the current operation, 'item' is a
394 visible. 'topic' is the current operation, 'item' is a
394 non-numeric marker of the current position (ie the currently
395 non-numeric marker of the current position (ie the currently
395 in-process file), 'pos' is the current numeric position (ie
396 in-process file), 'pos' is the current numeric position (ie
396 revision, bytes, etc.), unit is a corresponding unit label,
397 revision, bytes, etc.), unit is a corresponding unit label,
397 and total is the highest expected pos.
398 and total is the highest expected pos.
398
399
399 Multiple nested topics may be active at a time.
400 Multiple nested topics may be active at a time.
400
401
401 All topics should be marked closed by setting pos to None at
402 All topics should be marked closed by setting pos to None at
402 termination.
403 termination.
403 '''
404 '''
404
405
405 if pos == None or not self.debugflag:
406 if pos == None or not self.debugflag:
406 return
407 return
407
408
408 if unit:
409 if unit:
409 unit = ' ' + unit
410 unit = ' ' + unit
410 if item:
411 if item:
411 item = ' ' + item
412 item = ' ' + item
412
413
413 if total:
414 if total:
414 pct = 100.0 * pos / total
415 pct = 100.0 * pos / total
415 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
416 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
416 % (topic, item, pos, total, unit, pct))
417 % (topic, item, pos, total, unit, pct))
417 else:
418 else:
418 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
419 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
@@ -1,49 +1,51 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo "invalid" > $HGRCPATH
3 echo "invalid" > $HGRCPATH
4 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
4 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
5 echo "" > $HGRCPATH
5 echo "" > $HGRCPATH
6
6
7 # issue1199: escaping
7 # issue1199: escaping
8 hg init "foo%bar"
8 hg init "foo%bar"
9 hg clone "foo%bar" foobar
9 hg clone "foo%bar" foobar
10 p=`pwd`
10 p=`pwd`
11 cd foobar
11 cd foobar
12 cat .hg/hgrc | sed -e "s:$p:...:"
12 cat .hg/hgrc | sed -e "s:$p:...:"
13 hg paths | sed -e "s:$p:...:"
13 hg paths | sed -e "s:$p:...:"
14 hg showconfig | sed -e "s:$p:...:"
14 hg showconfig | sed -e "s:$p:...:"
15 cd ..
15 cd ..
16
16
17 # issue1829: wrong indentation
17 # issue1829: wrong indentation
18 echo '[foo]' > $HGRCPATH
18 echo '[foo]' > $HGRCPATH
19 echo ' x = y' >> $HGRCPATH
19 echo ' x = y' >> $HGRCPATH
20 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
20 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
21
21
22 python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
22 python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
23 > $HGRCPATH
23 > $HGRCPATH
24 hg showconfig foo
24 hg showconfig foo
25
25
26 echo '%include /no-such-file' > $HGRCPATH
26 echo '%include /no-such-file' > $HGRCPATH
27 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
27 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
28
28
29 # HGPLAIN
29 # HGPLAIN
30 cd ..
30 cd ..
31 p=`pwd`
31 p=`pwd`
32 echo "[ui]" > $HGRCPATH
32 echo "[ui]" > $HGRCPATH
33 echo "debug=true" >> $HGRCPATH
33 echo "debug=true" >> $HGRCPATH
34 echo "fallbackencoding=ASCII" >> $HGRCPATH
34 echo "fallbackencoding=ASCII" >> $HGRCPATH
35 echo "quiet=true" >> $HGRCPATH
35 echo "quiet=true" >> $HGRCPATH
36 echo "slash=true" >> $HGRCPATH
36 echo "slash=true" >> $HGRCPATH
37 echo "traceback=true" >> $HGRCPATH
37 echo "traceback=true" >> $HGRCPATH
38 echo "verbose=true" >> $HGRCPATH
38 echo "verbose=true" >> $HGRCPATH
39 echo "style=~/.hgstyle" >> $HGRCPATH
40 echo "logtemplate={node}" >> $HGRCPATH
39 echo "[defaults]" >> $HGRCPATH
41 echo "[defaults]" >> $HGRCPATH
40 echo "identify=-n" >> $HGRCPATH
42 echo "identify=-n" >> $HGRCPATH
41 echo "[alias]" >> $HGRCPATH
43 echo "[alias]" >> $HGRCPATH
42 echo "log=log -g" >> $HGRCPATH
44 echo "log=log -g" >> $HGRCPATH
43
45
44 echo '% customized hgrc'
46 echo '% customized hgrc'
45 hg showconfig | sed -e "s:$p:...:"
47 hg showconfig | sed -e "s:$p:...:"
46
48
47 echo '% plain hgrc'
49 echo '% plain hgrc'
48 HGPLAIN=; export HGPLAIN
50 HGPLAIN=; export HGPLAIN
49 hg showconfig --config ui.traceback=True --debug | sed -e "s:$p:...:"
51 hg showconfig --config ui.traceback=True --debug | sed -e "s:$p:...:"
@@ -1,26 +1,28 b''
1 hg: config error at $HGRCPATH:1: 'invalid'
1 hg: config error at $HGRCPATH:1: 'invalid'
2 updating to branch default
2 updating to branch default
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 [paths]
4 [paths]
5 default = .../foo%bar
5 default = .../foo%bar
6 default = .../foo%bar
6 default = .../foo%bar
7 bundle.mainreporoot=.../foobar
7 bundle.mainreporoot=.../foobar
8 paths.default=.../foo%bar
8 paths.default=.../foo%bar
9 hg: config error at $HGRCPATH:2: ' x = y'
9 hg: config error at $HGRCPATH:2: ' x = y'
10 foo.bar=a\nb\nc\nde\nfg
10 foo.bar=a\nb\nc\nde\nfg
11 foo.baz=bif cb
11 foo.baz=bif cb
12 hg: config error at $HGRCPATH:1: cannot include /no-such-file (No such file or directory)
12 hg: config error at $HGRCPATH:1: cannot include /no-such-file (No such file or directory)
13 % customized hgrc
13 % customized hgrc
14 .../.hgrc:11: alias.log=log -g
14 .../.hgrc:13: alias.log=log -g
15 .../.hgrc:9: defaults.identify=-n
15 .../.hgrc:11: defaults.identify=-n
16 .../.hgrc:2: ui.debug=true
16 .../.hgrc:2: ui.debug=true
17 .../.hgrc:3: ui.fallbackencoding=ASCII
17 .../.hgrc:3: ui.fallbackencoding=ASCII
18 .../.hgrc:4: ui.quiet=true
18 .../.hgrc:4: ui.quiet=true
19 .../.hgrc:5: ui.slash=true
19 .../.hgrc:5: ui.slash=true
20 .../.hgrc:6: ui.traceback=true
20 .../.hgrc:6: ui.traceback=true
21 .../.hgrc:7: ui.verbose=true
21 .../.hgrc:7: ui.verbose=true
22 .../.hgrc:8: ui.style=~/.hgstyle
23 .../.hgrc:9: ui.logtemplate={node}
22 % plain hgrc
24 % plain hgrc
23 none: ui.traceback=True
25 none: ui.traceback=True
24 none: ui.verbose=False
26 none: ui.verbose=False
25 none: ui.debug=True
27 none: ui.debug=True
26 none: ui.quiet=False
28 none: ui.quiet=False
General Comments 0
You need to be logged in to leave comments. Login now