##// END OF EJS Templates
make ui.expandpath better with default path.
Vadim Gelfer -
r2495:4a2a4d98 default
parent child Browse files
Show More
@@ -1,343 +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 return self.config("paths", loc, default or loc)
205 path = self.config("paths", loc)
206 if not path and default is not None:
207 path = self.config("paths", default)
208 return path
206 209
207 210 def write(self, *args):
208 211 if self.header:
209 212 if self.header != self.prev_header:
210 213 self.prev_header = self.header
211 214 self.write(*self.header)
212 215 self.header = []
213 216 for a in args:
214 217 sys.stdout.write(str(a))
215 218
216 219 def write_header(self, *args):
217 220 for a in args:
218 221 self.header.append(str(a))
219 222
220 223 def write_err(self, *args):
221 224 try:
222 225 if not sys.stdout.closed: sys.stdout.flush()
223 226 for a in args:
224 227 sys.stderr.write(str(a))
225 228 except IOError, inst:
226 229 if inst.errno != errno.EPIPE:
227 230 raise
228 231
229 232 def flush(self):
230 233 try: sys.stdout.flush()
231 234 except: pass
232 235 try: sys.stderr.flush()
233 236 except: pass
234 237
235 238 def readline(self):
236 239 return sys.stdin.readline()[:-1]
237 240 def prompt(self, msg, pat=None, default="y"):
238 241 if not self.interactive: return default
239 242 while 1:
240 243 self.write(msg, " ")
241 244 r = self.readline()
242 245 if not pat or re.match(pat, r):
243 246 return r
244 247 else:
245 248 self.write(_("unrecognized response\n"))
246 249 def getpass(self, prompt=None, default=None):
247 250 if not self.interactive: return default
248 251 return getpass.getpass(prompt or _('password: '))
249 252 def status(self, *msg):
250 253 if not self.quiet: self.write(*msg)
251 254 def warn(self, *msg):
252 255 self.write_err(*msg)
253 256 def note(self, *msg):
254 257 if self.verbose: self.write(*msg)
255 258 def debug(self, *msg):
256 259 if self.debugflag: self.write(*msg)
257 260 def edit(self, text, user):
258 261 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
259 262 text=True)
260 263 try:
261 264 f = os.fdopen(fd, "w")
262 265 f.write(text)
263 266 f.close()
264 267
265 268 editor = (os.environ.get("HGEDITOR") or
266 269 self.config("ui", "editor") or
267 270 os.environ.get("EDITOR", "vi"))
268 271
269 272 util.system("%s \"%s\"" % (editor, name),
270 273 environ={'HGUSER': user},
271 274 onerr=util.Abort, errprefix=_("edit failed"))
272 275
273 276 f = open(name)
274 277 t = f.read()
275 278 f.close()
276 279 t = re.sub("(?m)^HG:.*\n", "", t)
277 280 finally:
278 281 os.unlink(name)
279 282
280 283 return t
281 284
282 285 def sendmail(self):
283 286 '''send mail message. object returned has one method, sendmail.
284 287 call as sendmail(sender, list-of-recipients, msg).'''
285 288
286 289 def smtp():
287 290 '''send mail using smtp.'''
288 291
289 292 s = smtplib.SMTP()
290 293 mailhost = self.config('smtp', 'host')
291 294 if not mailhost:
292 295 raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
293 296 mailport = int(self.config('smtp', 'port', 25))
294 297 self.note(_('sending mail: smtp host %s, port %s\n') %
295 298 (mailhost, mailport))
296 299 s.connect(host=mailhost, port=mailport)
297 300 if self.configbool('smtp', 'tls'):
298 301 self.note(_('(using tls)\n'))
299 302 s.ehlo()
300 303 s.starttls()
301 304 s.ehlo()
302 305 username = self.config('smtp', 'username')
303 306 password = self.config('smtp', 'password')
304 307 if username and password:
305 308 self.note(_('(authenticating to mail server as %s)\n') %
306 309 (username))
307 310 s.login(username, password)
308 311 return s
309 312
310 313 class sendmail(object):
311 314 '''send mail using sendmail.'''
312 315
313 316 def __init__(self, ui, program):
314 317 self.ui = ui
315 318 self.program = program
316 319
317 320 def sendmail(self, sender, recipients, msg):
318 321 cmdline = '%s -f %s %s' % (
319 322 self.program, templater.email(sender),
320 323 ' '.join(map(templater.email, recipients)))
321 324 self.ui.note(_('sending mail: %s\n') % cmdline)
322 325 fp = os.popen(cmdline, 'w')
323 326 fp.write(msg)
324 327 ret = fp.close()
325 328 if ret:
326 329 raise util.Abort('%s %s' % (
327 330 os.path.basename(self.program.split(None, 1)[0]),
328 331 util.explain_exit(ret)[0]))
329 332
330 333 method = self.config('email', 'method', 'smtp')
331 334 if method == 'smtp':
332 335 mail = smtp()
333 336 else:
334 337 mail = sendmail(self, method)
335 338 return mail
336 339
337 340 def print_exc(self):
338 341 '''print exception traceback if traceback printing enabled.
339 342 only to call in exception handler. returns true if traceback
340 343 printed.'''
341 344 if self.traceback:
342 345 traceback.print_exc()
343 346 return self.traceback
General Comments 0
You need to be logged in to leave comments. Login now