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