##// END OF EJS Templates
Further cleanup of ui.py (changeset 74d569332f8b used one-char variable names).
Thomas Arendsen Hein -
r2403:9b074720 default
parent child Browse files
Show More
@@ -1,348 +1,344 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import ConfigParser
8 import ConfigParser
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "errno getpass os re smtplib socket sys tempfile")
11 demandload(globals(), "errno getpass os re smtplib socket sys tempfile")
12 demandload(globals(), "templater traceback util")
12 demandload(globals(), "templater traceback util")
13
13
14 class ui(object):
14 class ui(object):
15 def __init__(self, verbose=False, debug=False, quiet=False,
15 def __init__(self, verbose=False, debug=False, quiet=False,
16 interactive=True, traceback=False, parentui=None):
16 interactive=True, traceback=False, parentui=None):
17 self.overlay = {}
17 self.overlay = {}
18 if parentui is None:
18 if parentui is None:
19 # this is the parent of all ui children
19 # this is the parent of all ui children
20 self.parentui = None
20 self.parentui = None
21 self.cdata = ConfigParser.SafeConfigParser()
21 self.cdata = ConfigParser.SafeConfigParser()
22 self.readconfig(util.rcpath())
22 self.readconfig(util.rcpath())
23
23
24 self.quiet = self.configbool("ui", "quiet")
24 self.quiet = self.configbool("ui", "quiet")
25 self.verbose = self.configbool("ui", "verbose")
25 self.verbose = self.configbool("ui", "verbose")
26 self.debugflag = self.configbool("ui", "debug")
26 self.debugflag = self.configbool("ui", "debug")
27 self.interactive = self.configbool("ui", "interactive", True)
27 self.interactive = self.configbool("ui", "interactive", True)
28 self.traceback = traceback
28 self.traceback = traceback
29
29
30 self.updateopts(verbose, debug, quiet, interactive)
30 self.updateopts(verbose, debug, quiet, interactive)
31 self.diffcache = None
31 self.diffcache = None
32 self.header = []
32 self.header = []
33 self.prev_header = []
33 self.prev_header = []
34 self.revlogopts = self.configrevlog()
34 self.revlogopts = self.configrevlog()
35 else:
35 else:
36 # parentui may point to an ui object which is already a child
36 # parentui may point to an ui object which is already a child
37 self.parentui = parentui.parentui or parentui
37 self.parentui = parentui.parentui or parentui
38 parent_cdata = self.parentui.cdata
38 parent_cdata = self.parentui.cdata
39 self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
39 self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
40 # make interpolation work
40 # make interpolation work
41 for section in parent_cdata.sections():
41 for section in parent_cdata.sections():
42 self.cdata.add_section(section)
42 self.cdata.add_section(section)
43 for name, value in parent_cdata.items(section, raw=True):
43 for name, value in parent_cdata.items(section, raw=True):
44 self.cdata.set(section, name, value)
44 self.cdata.set(section, name, value)
45
45
46 def __getattr__(self, key):
46 def __getattr__(self, key):
47 return getattr(self.parentui, key)
47 return getattr(self.parentui, key)
48
48
49 def updateopts(self, verbose=False, debug=False, quiet=False,
49 def updateopts(self, verbose=False, debug=False, quiet=False,
50 interactive=True, traceback=False, config=[]):
50 interactive=True, traceback=False, config=[]):
51 self.quiet = (self.quiet or quiet) and not verbose and not debug
51 self.quiet = (self.quiet or quiet) and not verbose and not debug
52 self.verbose = (self.verbose or verbose) or debug
52 self.verbose = (self.verbose or verbose) or debug
53 self.debugflag = (self.debugflag or debug)
53 self.debugflag = (self.debugflag or debug)
54 self.interactive = (self.interactive and interactive)
54 self.interactive = (self.interactive and interactive)
55 self.traceback = self.traceback or traceback
55 self.traceback = self.traceback or traceback
56 for cfg in config:
56 for cfg in config:
57 try:
57 try:
58 name, value = cfg.split('=', 1)
58 name, value = cfg.split('=', 1)
59 section, name = name.split('.', 1)
59 section, name = name.split('.', 1)
60 if not self.cdata.has_section(section):
60 if not self.cdata.has_section(section):
61 self.cdata.add_section(section)
61 self.cdata.add_section(section)
62 if not section or not name:
62 if not section or not name:
63 raise IndexError
63 raise IndexError
64 self.cdata.set(section, name, value)
64 self.cdata.set(section, name, value)
65 except (IndexError, ValueError):
65 except (IndexError, ValueError):
66 raise util.Abort(_('malformed --config option: %s') % cfg)
66 raise util.Abort(_('malformed --config option: %s') % cfg)
67
67
68 def readconfig(self, fn, root=None):
68 def readconfig(self, fn, root=None):
69 if isinstance(fn, basestring):
69 if isinstance(fn, basestring):
70 fn = [fn]
70 fn = [fn]
71 for f in fn:
71 for f in fn:
72 try:
72 try:
73 self.cdata.read(f)
73 self.cdata.read(f)
74 except ConfigParser.ParsingError, inst:
74 except ConfigParser.ParsingError, inst:
75 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
75 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
76 # translate paths relative to root (or home) into absolute paths
76 # translate paths relative to root (or home) into absolute paths
77 if root is None:
77 if root is None:
78 root = os.path.expanduser('~')
78 root = os.path.expanduser('~')
79 for name, path in self.configitems("paths"):
79 for name, path in self.configitems("paths"):
80 if path and path.find("://") == -1 and not os.path.isabs(path):
80 if path and path.find("://") == -1 and not os.path.isabs(path):
81 self.cdata.set("paths", name, os.path.join(root, path))
81 self.cdata.set("paths", name, os.path.join(root, path))
82
82
83 def setconfig(self, section, name, val):
83 def setconfig(self, section, name, val):
84 self.overlay[(section, name)] = val
84 self.overlay[(section, name)] = val
85
85
86 def config(self, section, name, default=None):
86 def config(self, section, name, default=None):
87 if self.overlay.has_key((section, name)):
87 if self.overlay.has_key((section, name)):
88 return self.overlay[(section, name)]
88 return self.overlay[(section, name)]
89 if self.cdata.has_option(section, name):
89 if self.cdata.has_option(section, name):
90 try:
90 try:
91 return self.cdata.get(section, name)
91 return self.cdata.get(section, name)
92 except ConfigParser.InterpolationError, inst:
92 except ConfigParser.InterpolationError, inst:
93 raise util.Abort(_("Error in configuration:\n%s") % inst)
93 raise util.Abort(_("Error in configuration:\n%s") % inst)
94 if self.parentui is None:
94 if self.parentui is None:
95 return default
95 return default
96 else:
96 else:
97 return self.parentui.config(section, name, default)
97 return self.parentui.config(section, name, default)
98
98
99 def configbool(self, section, name, default=False):
99 def configbool(self, section, name, default=False):
100 if self.overlay.has_key((section, name)):
100 if self.overlay.has_key((section, name)):
101 return self.overlay[(section, name)]
101 return self.overlay[(section, name)]
102 if self.cdata.has_option(section, name):
102 if self.cdata.has_option(section, name):
103 try:
103 try:
104 return self.cdata.getboolean(section, name)
104 return self.cdata.getboolean(section, name)
105 except ConfigParser.InterpolationError, inst:
105 except ConfigParser.InterpolationError, inst:
106 raise util.Abort(_("Error in configuration:\n%s") % inst)
106 raise util.Abort(_("Error in configuration:\n%s") % inst)
107 if self.parentui is None:
107 if self.parentui is None:
108 return default
108 return default
109 else:
109 else:
110 return self.parentui.configbool(section, name, default)
110 return self.parentui.configbool(section, name, default)
111
111
112 def has_config(self, section):
112 def has_config(self, section):
113 '''tell whether section exists in config.'''
113 '''tell whether section exists in config.'''
114 return self.cdata.has_section(section)
114 return self.cdata.has_section(section)
115
115
116 def configitems(self, section):
116 def configitems(self, section):
117 items = {}
117 items = {}
118 if self.parentui is not None:
118 if self.parentui is not None:
119 items = dict(self.parentui.configitems(section))
119 items = dict(self.parentui.configitems(section))
120 if self.cdata.has_section(section):
120 if self.cdata.has_section(section):
121 try:
121 try:
122 items.update(dict(self.cdata.items(section)))
122 items.update(dict(self.cdata.items(section)))
123 except ConfigParser.InterpolationError, inst:
123 except ConfigParser.InterpolationError, inst:
124 raise util.Abort(_("Error in configuration:\n%s") % inst)
124 raise util.Abort(_("Error in configuration:\n%s") % inst)
125 x = items.items()
125 x = items.items()
126 x.sort()
126 x.sort()
127 return x
127 return x
128
128
129 def walkconfig(self, seen=None):
129 def walkconfig(self, seen=None):
130 if seen is None:
130 if seen is None:
131 seen = {}
131 seen = {}
132 for (section, name), value in self.overlay.iteritems():
132 for (section, name), value in self.overlay.iteritems():
133 yield section, name, value
133 yield section, name, value
134 seen[section, name] = 1
134 seen[section, name] = 1
135 for section in self.cdata.sections():
135 for section in self.cdata.sections():
136 for name, value in self.cdata.items(section):
136 for name, value in self.cdata.items(section):
137 if (section, name) in seen: continue
137 if (section, name) in seen: continue
138 yield section, name, value.replace('\n', '\\n')
138 yield section, name, value.replace('\n', '\\n')
139 seen[section, name] = 1
139 seen[section, name] = 1
140 if self.parentui is not None:
140 if self.parentui is not None:
141 for parent in self.parentui.walkconfig(seen):
141 for parent in self.parentui.walkconfig(seen):
142 yield parent
142 yield parent
143
143
144 def extensions(self):
144 def extensions(self):
145 ret = self.configitems("extensions")
145 result = self.configitems("extensions")
146 for i, (k, v) in enumerate(ret):
146 for i, (key, value) in enumerate(result):
147 if v: ret[i] = (k, os.path.expanduser(v))
147 if value:
148 return ret
148 result[i] = (key, os.path.expanduser(value))
149 return result
149
150
150 def hgignorefiles(self):
151 def hgignorefiles(self):
151 ret = []
152 result = []
152 for k, v in self.configitems("ui"):
153 for key, value in self.configitems("ui"):
153 if k == 'ignore' or k.startswith('ignore.'):
154 if key == 'ignore' or key.startswith('ignore.'):
154 ret.append(os.path.expanduser(v))
155 result.append(os.path.expanduser(value))
155 return ret
156 return result
156
157
157 def configrevlog(self):
158 def configrevlog(self):
158 ret = {}
159 result = {}
159 for k, v in self.configitems("revlog"):
160 for key, value in self.configitems("revlog"):
160 ret[k.lower()] = v
161 result[key.lower()] = value
161 return ret
162 return result
162
163
163 def diffopts(self):
164 def diffopts(self):
164 if self.diffcache:
165 if self.diffcache:
165 return self.diffcache
166 return self.diffcache
166 ret = { 'showfunc' : True, 'ignorews' : False}
167 result = {'showfunc': True, 'ignorews': False}
167 for k, v in self.configitems("diff"):
168 for key, value in self.configitems("diff"):
168 if v:
169 if value:
169 v = v.lower()
170 result[key.lower()] = (value.lower() == 'true')
170 if v == 'true':
171 self.diffcache = result
171 v = True
172 return result
172 else:
173 v = False
174 ret[k.lower()] = v
175 self.diffcache = ret
176 return ret
177
173
178 def username(self):
174 def username(self):
179 """Return default username to be used in commits.
175 """Return default username to be used in commits.
180
176
181 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
177 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
182 and stop searching if one of these is set.
178 and stop searching if one of these is set.
183 Abort if found username is an empty string to force specifying
179 Abort if found username is an empty string to force specifying
184 the commit user elsewhere, e.g. with line option or repo hgrc.
180 the commit user elsewhere, e.g. with line option or repo hgrc.
185 If not found, use ($LOGNAME or $USER or $LNAME or
181 If not found, use ($LOGNAME or $USER or $LNAME or
186 $USERNAME) +"@full.hostname".
182 $USERNAME) +"@full.hostname".
187 """
183 """
188 user = os.environ.get("HGUSER")
184 user = os.environ.get("HGUSER")
189 if user is None:
185 if user is None:
190 user = self.config("ui", "username")
186 user = self.config("ui", "username")
191 if user is None:
187 if user is None:
192 user = os.environ.get("EMAIL")
188 user = os.environ.get("EMAIL")
193 if user is None:
189 if user is None:
194 try:
190 try:
195 user = '%s@%s' % (getpass.getuser(), socket.getfqdn())
191 user = '%s@%s' % (getpass.getuser(), socket.getfqdn())
196 except KeyError:
192 except KeyError:
197 raise util.Abort(_("Please specify a username."))
193 raise util.Abort(_("Please specify a username."))
198 return user
194 return user
199
195
200 def shortuser(self, user):
196 def shortuser(self, user):
201 """Return a short representation of a user name or email address."""
197 """Return a short representation of a user name or email address."""
202 if not self.verbose: user = util.shortuser(user)
198 if not self.verbose: user = util.shortuser(user)
203 return user
199 return user
204
200
205 def expandpath(self, loc):
201 def expandpath(self, loc):
206 """Return repository location relative to cwd or from [paths]"""
202 """Return repository location relative to cwd or from [paths]"""
207 if loc.find("://") != -1 or os.path.exists(loc):
203 if loc.find("://") != -1 or os.path.exists(loc):
208 return loc
204 return loc
209
205
210 return self.config("paths", loc, loc)
206 return self.config("paths", loc, loc)
211
207
212 def write(self, *args):
208 def write(self, *args):
213 if self.header:
209 if self.header:
214 if self.header != self.prev_header:
210 if self.header != self.prev_header:
215 self.prev_header = self.header
211 self.prev_header = self.header
216 self.write(*self.header)
212 self.write(*self.header)
217 self.header = []
213 self.header = []
218 for a in args:
214 for a in args:
219 sys.stdout.write(str(a))
215 sys.stdout.write(str(a))
220
216
221 def write_header(self, *args):
217 def write_header(self, *args):
222 for a in args:
218 for a in args:
223 self.header.append(str(a))
219 self.header.append(str(a))
224
220
225 def write_err(self, *args):
221 def write_err(self, *args):
226 try:
222 try:
227 if not sys.stdout.closed: sys.stdout.flush()
223 if not sys.stdout.closed: sys.stdout.flush()
228 for a in args:
224 for a in args:
229 sys.stderr.write(str(a))
225 sys.stderr.write(str(a))
230 except IOError, inst:
226 except IOError, inst:
231 if inst.errno != errno.EPIPE:
227 if inst.errno != errno.EPIPE:
232 raise
228 raise
233
229
234 def flush(self):
230 def flush(self):
235 try: sys.stdout.flush()
231 try: sys.stdout.flush()
236 except: pass
232 except: pass
237 try: sys.stderr.flush()
233 try: sys.stderr.flush()
238 except: pass
234 except: pass
239
235
240 def readline(self):
236 def readline(self):
241 return sys.stdin.readline()[:-1]
237 return sys.stdin.readline()[:-1]
242 def prompt(self, msg, pat=None, default="y"):
238 def prompt(self, msg, pat=None, default="y"):
243 if not self.interactive: return default
239 if not self.interactive: return default
244 while 1:
240 while 1:
245 self.write(msg, " ")
241 self.write(msg, " ")
246 r = self.readline()
242 r = self.readline()
247 if not pat or re.match(pat, r):
243 if not pat or re.match(pat, r):
248 return r
244 return r
249 else:
245 else:
250 self.write(_("unrecognized response\n"))
246 self.write(_("unrecognized response\n"))
251 def getpass(self, prompt=None, default=None):
247 def getpass(self, prompt=None, default=None):
252 if not self.interactive: return default
248 if not self.interactive: return default
253 return getpass.getpass(prompt or _('password: '))
249 return getpass.getpass(prompt or _('password: '))
254 def status(self, *msg):
250 def status(self, *msg):
255 if not self.quiet: self.write(*msg)
251 if not self.quiet: self.write(*msg)
256 def warn(self, *msg):
252 def warn(self, *msg):
257 self.write_err(*msg)
253 self.write_err(*msg)
258 def note(self, *msg):
254 def note(self, *msg):
259 if self.verbose: self.write(*msg)
255 if self.verbose: self.write(*msg)
260 def debug(self, *msg):
256 def debug(self, *msg):
261 if self.debugflag: self.write(*msg)
257 if self.debugflag: self.write(*msg)
262 def edit(self, text, user):
258 def edit(self, text, user):
263 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
259 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
264 text=True)
260 text=True)
265 try:
261 try:
266 f = os.fdopen(fd, "w")
262 f = os.fdopen(fd, "w")
267 f.write(text)
263 f.write(text)
268 f.close()
264 f.close()
269
265
270 editor = (os.environ.get("HGEDITOR") or
266 editor = (os.environ.get("HGEDITOR") or
271 self.config("ui", "editor") or
267 self.config("ui", "editor") or
272 os.environ.get("EDITOR", "vi"))
268 os.environ.get("EDITOR", "vi"))
273
269
274 util.system("%s \"%s\"" % (editor, name),
270 util.system("%s \"%s\"" % (editor, name),
275 environ={'HGUSER': user},
271 environ={'HGUSER': user},
276 onerr=util.Abort, errprefix=_("edit failed"))
272 onerr=util.Abort, errprefix=_("edit failed"))
277
273
278 f = open(name)
274 f = open(name)
279 t = f.read()
275 t = f.read()
280 f.close()
276 f.close()
281 t = re.sub("(?m)^HG:.*\n", "", t)
277 t = re.sub("(?m)^HG:.*\n", "", t)
282 finally:
278 finally:
283 os.unlink(name)
279 os.unlink(name)
284
280
285 return t
281 return t
286
282
287 def sendmail(self):
283 def sendmail(self):
288 '''send mail message. object returned has one method, sendmail.
284 '''send mail message. object returned has one method, sendmail.
289 call as sendmail(sender, list-of-recipients, msg).'''
285 call as sendmail(sender, list-of-recipients, msg).'''
290
286
291 def smtp():
287 def smtp():
292 '''send mail using smtp.'''
288 '''send mail using smtp.'''
293
289
294 s = smtplib.SMTP()
290 s = smtplib.SMTP()
295 mailhost = self.config('smtp', 'host')
291 mailhost = self.config('smtp', 'host')
296 if not mailhost:
292 if not mailhost:
297 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
293 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
298 mailport = int(self.config('smtp', 'port', 25))
294 mailport = int(self.config('smtp', 'port', 25))
299 self.note(_('sending mail: smtp host %s, port %s\n') %
295 self.note(_('sending mail: smtp host %s, port %s\n') %
300 (mailhost, mailport))
296 (mailhost, mailport))
301 s.connect(host=mailhost, port=mailport)
297 s.connect(host=mailhost, port=mailport)
302 if self.configbool('smtp', 'tls'):
298 if self.configbool('smtp', 'tls'):
303 self.note(_('(using tls)\n'))
299 self.note(_('(using tls)\n'))
304 s.ehlo()
300 s.ehlo()
305 s.starttls()
301 s.starttls()
306 s.ehlo()
302 s.ehlo()
307 username = self.config('smtp', 'username')
303 username = self.config('smtp', 'username')
308 password = self.config('smtp', 'password')
304 password = self.config('smtp', 'password')
309 if username and password:
305 if username and password:
310 self.note(_('(authenticating to mail server as %s)\n') %
306 self.note(_('(authenticating to mail server as %s)\n') %
311 (username))
307 (username))
312 s.login(username, password)
308 s.login(username, password)
313 return s
309 return s
314
310
315 class sendmail(object):
311 class sendmail(object):
316 '''send mail using sendmail.'''
312 '''send mail using sendmail.'''
317
313
318 def __init__(self, ui, program):
314 def __init__(self, ui, program):
319 self.ui = ui
315 self.ui = ui
320 self.program = program
316 self.program = program
321
317
322 def sendmail(self, sender, recipients, msg):
318 def sendmail(self, sender, recipients, msg):
323 cmdline = '%s -f %s %s' % (
319 cmdline = '%s -f %s %s' % (
324 self.program, templater.email(sender),
320 self.program, templater.email(sender),
325 ' '.join(map(templater.email, recipients)))
321 ' '.join(map(templater.email, recipients)))
326 self.ui.note(_('sending mail: %s\n') % cmdline)
322 self.ui.note(_('sending mail: %s\n') % cmdline)
327 fp = os.popen(cmdline, 'w')
323 fp = os.popen(cmdline, 'w')
328 fp.write(msg)
324 fp.write(msg)
329 ret = fp.close()
325 ret = fp.close()
330 if ret:
326 if ret:
331 raise util.Abort('%s %s' % (
327 raise util.Abort('%s %s' % (
332 os.path.basename(self.program.split(None, 1)[0]),
328 os.path.basename(self.program.split(None, 1)[0]),
333 util.explain_exit(ret)[0]))
329 util.explain_exit(ret)[0]))
334
330
335 method = self.config('email', 'method', 'smtp')
331 method = self.config('email', 'method', 'smtp')
336 if method == 'smtp':
332 if method == 'smtp':
337 mail = smtp()
333 mail = smtp()
338 else:
334 else:
339 mail = sendmail(self, method)
335 mail = sendmail(self, method)
340 return mail
336 return mail
341
337
342 def print_exc(self):
338 def print_exc(self):
343 '''print exception traceback if traceback printing enabled.
339 '''print exception traceback if traceback printing enabled.
344 only to call in exception handler. returns true if traceback
340 only to call in exception handler. returns true if traceback
345 printed.'''
341 printed.'''
346 if self.traceback:
342 if self.traceback:
347 traceback.print_exc()
343 traceback.print_exc()
348 return self.traceback
344 return self.traceback
General Comments 0
You need to be logged in to leave comments. Login now