##// END OF EJS Templates
Cleanup: unifiy the coding style in the ui.py configitems forwarders....
Markus F.X.J. Oberhumer -
r2388:74d56933 default
parent child Browse files
Show More
@@ -1,349 +1,345
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 return self.configitems("extensions")
145 return self.configitems("extensions")
146
146
147 def hgignorefiles(self):
147 def hgignorefiles(self):
148 result = []
148 ret = []
149 cfgitems = self.configitems("ui")
149 for k, v in self.configitems("ui"):
150 for key, value in cfgitems:
150 if k == 'ignore' or k.startswith('ignore.'):
151 if key == 'ignore' or key.startswith('ignore.'):
151 ret.append(os.path.expanduser(v))
152 path = os.path.expanduser(value)
152 return ret
153 result.append(path)
154 return result
155
153
156 def configrevlog(self):
154 def configrevlog(self):
157 ret = {}
155 ret = {}
158 for x in self.configitems("revlog"):
156 for k, v in self.configitems("revlog"):
159 k = x[0].lower()
157 ret[k.lower()] = v
160 ret[k] = x[1]
161 return ret
158 return ret
159
162 def diffopts(self):
160 def diffopts(self):
163 if self.diffcache:
161 if self.diffcache:
164 return self.diffcache
162 return self.diffcache
165 ret = { 'showfunc' : True, 'ignorews' : False}
163 ret = { 'showfunc' : True, 'ignorews' : False}
166 for x in self.configitems("diff"):
164 for k, v in self.configitems("diff"):
167 k = x[0].lower()
168 v = x[1]
169 if v:
165 if v:
170 v = v.lower()
166 v = v.lower()
171 if v == 'true':
167 if v == 'true':
172 value = True
168 v = True
173 else:
169 else:
174 value = False
170 v = False
175 ret[k] = value
171 ret[k.lower()] = v
176 self.diffcache = ret
172 self.diffcache = ret
177 return ret
173 return ret
178
174
179 def username(self):
175 def username(self):
180 """Return default username to be used in commits.
176 """Return default username to be used in commits.
181
177
182 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
178 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
183 and stop searching if one of these is set.
179 and stop searching if one of these is set.
184 Abort if found username is an empty string to force specifying
180 Abort if found username is an empty string to force specifying
185 the commit user elsewhere, e.g. with line option or repo hgrc.
181 the commit user elsewhere, e.g. with line option or repo hgrc.
186 If not found, use ($LOGNAME or $USER or $LNAME or
182 If not found, use ($LOGNAME or $USER or $LNAME or
187 $USERNAME) +"@full.hostname".
183 $USERNAME) +"@full.hostname".
188 """
184 """
189 user = os.environ.get("HGUSER")
185 user = os.environ.get("HGUSER")
190 if user is None:
186 if user is None:
191 user = self.config("ui", "username")
187 user = self.config("ui", "username")
192 if user is None:
188 if user is None:
193 user = os.environ.get("EMAIL")
189 user = os.environ.get("EMAIL")
194 if user is None:
190 if user is None:
195 try:
191 try:
196 user = '%s@%s' % (getpass.getuser(), socket.getfqdn())
192 user = '%s@%s' % (getpass.getuser(), socket.getfqdn())
197 except KeyError:
193 except KeyError:
198 raise util.Abort(_("Please specify a username."))
194 raise util.Abort(_("Please specify a username."))
199 return user
195 return user
200
196
201 def shortuser(self, user):
197 def shortuser(self, user):
202 """Return a short representation of a user name or email address."""
198 """Return a short representation of a user name or email address."""
203 if not self.verbose: user = util.shortuser(user)
199 if not self.verbose: user = util.shortuser(user)
204 return user
200 return user
205
201
206 def expandpath(self, loc):
202 def expandpath(self, loc):
207 """Return repository location relative to cwd or from [paths]"""
203 """Return repository location relative to cwd or from [paths]"""
208 if loc.find("://") != -1 or os.path.exists(loc):
204 if loc.find("://") != -1 or os.path.exists(loc):
209 return loc
205 return loc
210
206
211 return self.config("paths", loc, loc)
207 return self.config("paths", loc, loc)
212
208
213 def write(self, *args):
209 def write(self, *args):
214 if self.header:
210 if self.header:
215 if self.header != self.prev_header:
211 if self.header != self.prev_header:
216 self.prev_header = self.header
212 self.prev_header = self.header
217 self.write(*self.header)
213 self.write(*self.header)
218 self.header = []
214 self.header = []
219 for a in args:
215 for a in args:
220 sys.stdout.write(str(a))
216 sys.stdout.write(str(a))
221
217
222 def write_header(self, *args):
218 def write_header(self, *args):
223 for a in args:
219 for a in args:
224 self.header.append(str(a))
220 self.header.append(str(a))
225
221
226 def write_err(self, *args):
222 def write_err(self, *args):
227 try:
223 try:
228 if not sys.stdout.closed: sys.stdout.flush()
224 if not sys.stdout.closed: sys.stdout.flush()
229 for a in args:
225 for a in args:
230 sys.stderr.write(str(a))
226 sys.stderr.write(str(a))
231 except IOError, inst:
227 except IOError, inst:
232 if inst.errno != errno.EPIPE:
228 if inst.errno != errno.EPIPE:
233 raise
229 raise
234
230
235 def flush(self):
231 def flush(self):
236 try: sys.stdout.flush()
232 try: sys.stdout.flush()
237 except: pass
233 except: pass
238 try: sys.stderr.flush()
234 try: sys.stderr.flush()
239 except: pass
235 except: pass
240
236
241 def readline(self):
237 def readline(self):
242 return sys.stdin.readline()[:-1]
238 return sys.stdin.readline()[:-1]
243 def prompt(self, msg, pat=None, default="y"):
239 def prompt(self, msg, pat=None, default="y"):
244 if not self.interactive: return default
240 if not self.interactive: return default
245 while 1:
241 while 1:
246 self.write(msg, " ")
242 self.write(msg, " ")
247 r = self.readline()
243 r = self.readline()
248 if not pat or re.match(pat, r):
244 if not pat or re.match(pat, r):
249 return r
245 return r
250 else:
246 else:
251 self.write(_("unrecognized response\n"))
247 self.write(_("unrecognized response\n"))
252 def getpass(self, prompt=None, default=None):
248 def getpass(self, prompt=None, default=None):
253 if not self.interactive: return default
249 if not self.interactive: return default
254 return getpass.getpass(prompt or _('password: '))
250 return getpass.getpass(prompt or _('password: '))
255 def status(self, *msg):
251 def status(self, *msg):
256 if not self.quiet: self.write(*msg)
252 if not self.quiet: self.write(*msg)
257 def warn(self, *msg):
253 def warn(self, *msg):
258 self.write_err(*msg)
254 self.write_err(*msg)
259 def note(self, *msg):
255 def note(self, *msg):
260 if self.verbose: self.write(*msg)
256 if self.verbose: self.write(*msg)
261 def debug(self, *msg):
257 def debug(self, *msg):
262 if self.debugflag: self.write(*msg)
258 if self.debugflag: self.write(*msg)
263 def edit(self, text, user):
259 def edit(self, text, user):
264 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
260 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
265 text=True)
261 text=True)
266 try:
262 try:
267 f = os.fdopen(fd, "w")
263 f = os.fdopen(fd, "w")
268 f.write(text)
264 f.write(text)
269 f.close()
265 f.close()
270
266
271 editor = (os.environ.get("HGEDITOR") or
267 editor = (os.environ.get("HGEDITOR") or
272 self.config("ui", "editor") or
268 self.config("ui", "editor") or
273 os.environ.get("EDITOR", "vi"))
269 os.environ.get("EDITOR", "vi"))
274
270
275 util.system("%s \"%s\"" % (editor, name),
271 util.system("%s \"%s\"" % (editor, name),
276 environ={'HGUSER': user},
272 environ={'HGUSER': user},
277 onerr=util.Abort, errprefix=_("edit failed"))
273 onerr=util.Abort, errprefix=_("edit failed"))
278
274
279 f = open(name)
275 f = open(name)
280 t = f.read()
276 t = f.read()
281 f.close()
277 f.close()
282 t = re.sub("(?m)^HG:.*\n", "", t)
278 t = re.sub("(?m)^HG:.*\n", "", t)
283 finally:
279 finally:
284 os.unlink(name)
280 os.unlink(name)
285
281
286 return t
282 return t
287
283
288 def sendmail(self):
284 def sendmail(self):
289 '''send mail message. object returned has one method, sendmail.
285 '''send mail message. object returned has one method, sendmail.
290 call as sendmail(sender, list-of-recipients, msg).'''
286 call as sendmail(sender, list-of-recipients, msg).'''
291
287
292 def smtp():
288 def smtp():
293 '''send mail using smtp.'''
289 '''send mail using smtp.'''
294
290
295 s = smtplib.SMTP()
291 s = smtplib.SMTP()
296 mailhost = self.config('smtp', 'host')
292 mailhost = self.config('smtp', 'host')
297 if not mailhost:
293 if not mailhost:
298 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
294 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
299 mailport = int(self.config('smtp', 'port', 25))
295 mailport = int(self.config('smtp', 'port', 25))
300 self.note(_('sending mail: smtp host %s, port %s\n') %
296 self.note(_('sending mail: smtp host %s, port %s\n') %
301 (mailhost, mailport))
297 (mailhost, mailport))
302 s.connect(host=mailhost, port=mailport)
298 s.connect(host=mailhost, port=mailport)
303 if self.configbool('smtp', 'tls'):
299 if self.configbool('smtp', 'tls'):
304 self.note(_('(using tls)\n'))
300 self.note(_('(using tls)\n'))
305 s.ehlo()
301 s.ehlo()
306 s.starttls()
302 s.starttls()
307 s.ehlo()
303 s.ehlo()
308 username = self.config('smtp', 'username')
304 username = self.config('smtp', 'username')
309 password = self.config('smtp', 'password')
305 password = self.config('smtp', 'password')
310 if username and password:
306 if username and password:
311 self.note(_('(authenticating to mail server as %s)\n') %
307 self.note(_('(authenticating to mail server as %s)\n') %
312 (username))
308 (username))
313 s.login(username, password)
309 s.login(username, password)
314 return s
310 return s
315
311
316 class sendmail(object):
312 class sendmail(object):
317 '''send mail using sendmail.'''
313 '''send mail using sendmail.'''
318
314
319 def __init__(self, ui, program):
315 def __init__(self, ui, program):
320 self.ui = ui
316 self.ui = ui
321 self.program = program
317 self.program = program
322
318
323 def sendmail(self, sender, recipients, msg):
319 def sendmail(self, sender, recipients, msg):
324 cmdline = '%s -f %s %s' % (
320 cmdline = '%s -f %s %s' % (
325 self.program, templater.email(sender),
321 self.program, templater.email(sender),
326 ' '.join(map(templater.email, recipients)))
322 ' '.join(map(templater.email, recipients)))
327 self.ui.note(_('sending mail: %s\n') % cmdline)
323 self.ui.note(_('sending mail: %s\n') % cmdline)
328 fp = os.popen(cmdline, 'w')
324 fp = os.popen(cmdline, 'w')
329 fp.write(msg)
325 fp.write(msg)
330 ret = fp.close()
326 ret = fp.close()
331 if ret:
327 if ret:
332 raise util.Abort('%s %s' % (
328 raise util.Abort('%s %s' % (
333 os.path.basename(self.program.split(None, 1)[0]),
329 os.path.basename(self.program.split(None, 1)[0]),
334 util.explain_exit(ret)[0]))
330 util.explain_exit(ret)[0]))
335
331
336 method = self.config('email', 'method', 'smtp')
332 method = self.config('email', 'method', 'smtp')
337 if method == 'smtp':
333 if method == 'smtp':
338 mail = smtp()
334 mail = smtp()
339 else:
335 else:
340 mail = sendmail(self, method)
336 mail = sendmail(self, method)
341 return mail
337 return mail
342
338
343 def print_exc(self):
339 def print_exc(self):
344 '''print exception traceback if traceback printing enabled.
340 '''print exception traceback if traceback printing enabled.
345 only to call in exception handler. returns true if traceback
341 only to call in exception handler. returns true if traceback
346 printed.'''
342 printed.'''
347 if self.traceback:
343 if self.traceback:
348 traceback.print_exc()
344 traceback.print_exc()
349 return self.traceback
345 return self.traceback
General Comments 0
You need to be logged in to leave comments. Login now