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