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