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