##// END OF EJS Templates
ui: allow default when prompting
Matt Mackall -
r5709:9dc26941 default
parent child Browse files
Show More
@@ -1,473 +1,475
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 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 from i18n import _
8 from i18n import _
9 import errno, getpass, os, re, socket, sys, tempfile
9 import errno, getpass, os, re, socket, sys, tempfile
10 import ConfigParser, traceback, util
10 import ConfigParser, traceback, util
11
11
12 def dupconfig(orig):
12 def dupconfig(orig):
13 new = util.configparser(orig.defaults())
13 new = util.configparser(orig.defaults())
14 updateconfig(orig, new)
14 updateconfig(orig, new)
15 return new
15 return new
16
16
17 def updateconfig(source, dest, sections=None):
17 def updateconfig(source, dest, sections=None):
18 if not sections:
18 if not sections:
19 sections = source.sections()
19 sections = source.sections()
20 for section in sections:
20 for section in sections:
21 if not dest.has_section(section):
21 if not dest.has_section(section):
22 dest.add_section(section)
22 dest.add_section(section)
23 for name, value in source.items(section, raw=True):
23 for name, value in source.items(section, raw=True):
24 dest.set(section, name, value)
24 dest.set(section, name, value)
25
25
26 class ui(object):
26 class ui(object):
27 _isatty = None
27 _isatty = None
28
28
29 def __init__(self, verbose=False, debug=False, quiet=False,
29 def __init__(self, verbose=False, debug=False, quiet=False,
30 interactive=True, traceback=False, report_untrusted=True,
30 interactive=True, traceback=False, report_untrusted=True,
31 parentui=None):
31 parentui=None):
32 self.overlay = None
32 self.overlay = None
33 self.buffers = []
33 self.buffers = []
34 if parentui is None:
34 if parentui is None:
35 # this is the parent of all ui children
35 # this is the parent of all ui children
36 self.parentui = None
36 self.parentui = None
37 self.quiet = quiet
37 self.quiet = quiet
38 self.verbose = verbose
38 self.verbose = verbose
39 self.debugflag = debug
39 self.debugflag = debug
40 self.interactive = interactive
40 self.interactive = interactive
41 self.traceback = traceback
41 self.traceback = traceback
42 self.report_untrusted = report_untrusted
42 self.report_untrusted = report_untrusted
43 self.trusted_users = {}
43 self.trusted_users = {}
44 self.trusted_groups = {}
44 self.trusted_groups = {}
45 # if ucdata is not None, its keys must be a superset of cdata's
45 # if ucdata is not None, its keys must be a superset of cdata's
46 self.cdata = util.configparser()
46 self.cdata = util.configparser()
47 self.ucdata = None
47 self.ucdata = None
48 # we always trust global config files
48 # we always trust global config files
49 self.check_trusted = False
49 self.check_trusted = False
50 self.readconfig(util.rcpath())
50 self.readconfig(util.rcpath())
51 self.check_trusted = True
51 self.check_trusted = True
52 self.updateopts(verbose, debug, quiet, interactive)
52 self.updateopts(verbose, debug, quiet, interactive)
53 else:
53 else:
54 # parentui may point to an ui object which is already a child
54 # parentui may point to an ui object which is already a child
55 self.parentui = parentui.parentui or parentui
55 self.parentui = parentui.parentui or parentui
56 self.trusted_users = parentui.trusted_users.copy()
56 self.trusted_users = parentui.trusted_users.copy()
57 self.trusted_groups = parentui.trusted_groups.copy()
57 self.trusted_groups = parentui.trusted_groups.copy()
58 self.cdata = dupconfig(self.parentui.cdata)
58 self.cdata = dupconfig(self.parentui.cdata)
59 if self.parentui.ucdata:
59 if self.parentui.ucdata:
60 self.ucdata = dupconfig(self.parentui.ucdata)
60 self.ucdata = dupconfig(self.parentui.ucdata)
61 if self.parentui.overlay:
61 if self.parentui.overlay:
62 self.overlay = dupconfig(self.parentui.overlay)
62 self.overlay = dupconfig(self.parentui.overlay)
63
63
64 def __getattr__(self, key):
64 def __getattr__(self, key):
65 return getattr(self.parentui, key)
65 return getattr(self.parentui, key)
66
66
67 def isatty(self):
67 def isatty(self):
68 if ui._isatty is None:
68 if ui._isatty is None:
69 ui._isatty = sys.stdin.isatty()
69 ui._isatty = sys.stdin.isatty()
70 return ui._isatty
70 return ui._isatty
71
71
72 def updateopts(self, verbose=False, debug=False, quiet=False,
72 def updateopts(self, verbose=False, debug=False, quiet=False,
73 interactive=True, traceback=False, config=[]):
73 interactive=True, traceback=False, config=[]):
74 for section, name, value in config:
74 for section, name, value in config:
75 self.setconfig(section, name, value)
75 self.setconfig(section, name, value)
76
76
77 if quiet or verbose or debug:
77 if quiet or verbose or debug:
78 self.setconfig('ui', 'quiet', str(bool(quiet)))
78 self.setconfig('ui', 'quiet', str(bool(quiet)))
79 self.setconfig('ui', 'verbose', str(bool(verbose)))
79 self.setconfig('ui', 'verbose', str(bool(verbose)))
80 self.setconfig('ui', 'debug', str(bool(debug)))
80 self.setconfig('ui', 'debug', str(bool(debug)))
81
81
82 self.verbosity_constraints()
82 self.verbosity_constraints()
83
83
84 if not interactive:
84 if not interactive:
85 self.setconfig('ui', 'interactive', 'False')
85 self.setconfig('ui', 'interactive', 'False')
86 self.interactive = False
86 self.interactive = False
87
87
88 self.traceback = self.traceback or traceback
88 self.traceback = self.traceback or traceback
89
89
90 def verbosity_constraints(self):
90 def verbosity_constraints(self):
91 self.quiet = self.configbool('ui', 'quiet')
91 self.quiet = self.configbool('ui', 'quiet')
92 self.verbose = self.configbool('ui', 'verbose')
92 self.verbose = self.configbool('ui', 'verbose')
93 self.debugflag = self.configbool('ui', 'debug')
93 self.debugflag = self.configbool('ui', 'debug')
94
94
95 if self.debugflag:
95 if self.debugflag:
96 self.verbose = True
96 self.verbose = True
97 self.quiet = False
97 self.quiet = False
98 elif self.verbose and self.quiet:
98 elif self.verbose and self.quiet:
99 self.quiet = self.verbose = False
99 self.quiet = self.verbose = False
100
100
101 def _is_trusted(self, fp, f, warn=True):
101 def _is_trusted(self, fp, f, warn=True):
102 if not self.check_trusted:
102 if not self.check_trusted:
103 return True
103 return True
104 st = util.fstat(fp)
104 st = util.fstat(fp)
105 if util.isowner(fp, st):
105 if util.isowner(fp, st):
106 return True
106 return True
107 tusers = self.trusted_users
107 tusers = self.trusted_users
108 tgroups = self.trusted_groups
108 tgroups = self.trusted_groups
109 if not tusers:
109 if not tusers:
110 user = util.username()
110 user = util.username()
111 if user is not None:
111 if user is not None:
112 self.trusted_users[user] = 1
112 self.trusted_users[user] = 1
113 self.fixconfig(section='trusted')
113 self.fixconfig(section='trusted')
114 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
114 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
115 user = util.username(st.st_uid)
115 user = util.username(st.st_uid)
116 group = util.groupname(st.st_gid)
116 group = util.groupname(st.st_gid)
117 if user not in tusers and group not in tgroups:
117 if user not in tusers and group not in tgroups:
118 if warn and self.report_untrusted:
118 if warn and self.report_untrusted:
119 self.warn(_('Not trusting file %s from untrusted '
119 self.warn(_('Not trusting file %s from untrusted '
120 'user %s, group %s\n') % (f, user, group))
120 'user %s, group %s\n') % (f, user, group))
121 return False
121 return False
122 return True
122 return True
123
123
124 def readconfig(self, fn, root=None):
124 def readconfig(self, fn, root=None):
125 if isinstance(fn, basestring):
125 if isinstance(fn, basestring):
126 fn = [fn]
126 fn = [fn]
127 for f in fn:
127 for f in fn:
128 try:
128 try:
129 fp = open(f)
129 fp = open(f)
130 except IOError:
130 except IOError:
131 continue
131 continue
132 cdata = self.cdata
132 cdata = self.cdata
133 trusted = self._is_trusted(fp, f)
133 trusted = self._is_trusted(fp, f)
134 if not trusted:
134 if not trusted:
135 if self.ucdata is None:
135 if self.ucdata is None:
136 self.ucdata = dupconfig(self.cdata)
136 self.ucdata = dupconfig(self.cdata)
137 cdata = self.ucdata
137 cdata = self.ucdata
138 elif self.ucdata is not None:
138 elif self.ucdata is not None:
139 # use a separate configparser, so that we don't accidentally
139 # use a separate configparser, so that we don't accidentally
140 # override ucdata settings later on.
140 # override ucdata settings later on.
141 cdata = util.configparser()
141 cdata = util.configparser()
142
142
143 try:
143 try:
144 cdata.readfp(fp, f)
144 cdata.readfp(fp, f)
145 except ConfigParser.ParsingError, inst:
145 except ConfigParser.ParsingError, inst:
146 msg = _("Failed to parse %s\n%s") % (f, inst)
146 msg = _("Failed to parse %s\n%s") % (f, inst)
147 if trusted:
147 if trusted:
148 raise util.Abort(msg)
148 raise util.Abort(msg)
149 self.warn(_("Ignored: %s\n") % msg)
149 self.warn(_("Ignored: %s\n") % msg)
150
150
151 if trusted:
151 if trusted:
152 if cdata != self.cdata:
152 if cdata != self.cdata:
153 updateconfig(cdata, self.cdata)
153 updateconfig(cdata, self.cdata)
154 if self.ucdata is not None:
154 if self.ucdata is not None:
155 updateconfig(cdata, self.ucdata)
155 updateconfig(cdata, self.ucdata)
156 # override data from config files with data set with ui.setconfig
156 # override data from config files with data set with ui.setconfig
157 if self.overlay:
157 if self.overlay:
158 updateconfig(self.overlay, self.cdata)
158 updateconfig(self.overlay, self.cdata)
159 if root is None:
159 if root is None:
160 root = os.path.expanduser('~')
160 root = os.path.expanduser('~')
161 self.fixconfig(root=root)
161 self.fixconfig(root=root)
162
162
163 def readsections(self, filename, *sections):
163 def readsections(self, filename, *sections):
164 """Read filename and add only the specified sections to the config data
164 """Read filename and add only the specified sections to the config data
165
165
166 The settings are added to the trusted config data.
166 The settings are added to the trusted config data.
167 """
167 """
168 if not sections:
168 if not sections:
169 return
169 return
170
170
171 cdata = util.configparser()
171 cdata = util.configparser()
172 try:
172 try:
173 try:
173 try:
174 fp = open(filename)
174 fp = open(filename)
175 except IOError, inst:
175 except IOError, inst:
176 raise util.Abort(_("unable to open %s: %s") %
176 raise util.Abort(_("unable to open %s: %s") %
177 (filename, getattr(inst, "strerror", inst)))
177 (filename, getattr(inst, "strerror", inst)))
178 try:
178 try:
179 cdata.readfp(fp, filename)
179 cdata.readfp(fp, filename)
180 finally:
180 finally:
181 fp.close()
181 fp.close()
182 except ConfigParser.ParsingError, inst:
182 except ConfigParser.ParsingError, inst:
183 raise util.Abort(_("failed to parse %s\n%s") % (filename, inst))
183 raise util.Abort(_("failed to parse %s\n%s") % (filename, inst))
184
184
185 for section in sections:
185 for section in sections:
186 if not cdata.has_section(section):
186 if not cdata.has_section(section):
187 cdata.add_section(section)
187 cdata.add_section(section)
188
188
189 updateconfig(cdata, self.cdata, sections)
189 updateconfig(cdata, self.cdata, sections)
190 if self.ucdata:
190 if self.ucdata:
191 updateconfig(cdata, self.ucdata, sections)
191 updateconfig(cdata, self.ucdata, sections)
192
192
193 def fixconfig(self, section=None, name=None, value=None, root=None):
193 def fixconfig(self, section=None, name=None, value=None, root=None):
194 # translate paths relative to root (or home) into absolute paths
194 # translate paths relative to root (or home) into absolute paths
195 if section is None or section == 'paths':
195 if section is None or section == 'paths':
196 if root is None:
196 if root is None:
197 root = os.getcwd()
197 root = os.getcwd()
198 items = section and [(name, value)] or []
198 items = section and [(name, value)] or []
199 for cdata in self.cdata, self.ucdata, self.overlay:
199 for cdata in self.cdata, self.ucdata, self.overlay:
200 if not cdata: continue
200 if not cdata: continue
201 if not items and cdata.has_section('paths'):
201 if not items and cdata.has_section('paths'):
202 pathsitems = cdata.items('paths')
202 pathsitems = cdata.items('paths')
203 else:
203 else:
204 pathsitems = items
204 pathsitems = items
205 for n, path in pathsitems:
205 for n, path in pathsitems:
206 if path and "://" not in path and not os.path.isabs(path):
206 if path and "://" not in path and not os.path.isabs(path):
207 cdata.set("paths", n, os.path.join(root, path))
207 cdata.set("paths", n, os.path.join(root, path))
208
208
209 # update verbosity/interactive/report_untrusted settings
209 # update verbosity/interactive/report_untrusted settings
210 if section is None or section == 'ui':
210 if section is None or section == 'ui':
211 if name is None or name in ('quiet', 'verbose', 'debug'):
211 if name is None or name in ('quiet', 'verbose', 'debug'):
212 self.verbosity_constraints()
212 self.verbosity_constraints()
213 if name is None or name == 'interactive':
213 if name is None or name == 'interactive':
214 interactive = self.configbool("ui", "interactive", None)
214 interactive = self.configbool("ui", "interactive", None)
215 if interactive is None and self.interactive:
215 if interactive is None and self.interactive:
216 self.interactive = self.isatty()
216 self.interactive = self.isatty()
217 else:
217 else:
218 self.interactive = interactive
218 self.interactive = interactive
219 if name is None or name == 'report_untrusted':
219 if name is None or name == 'report_untrusted':
220 self.report_untrusted = (
220 self.report_untrusted = (
221 self.configbool("ui", "report_untrusted", True))
221 self.configbool("ui", "report_untrusted", True))
222
222
223 # update trust information
223 # update trust information
224 if (section is None or section == 'trusted') and self.trusted_users:
224 if (section is None or section == 'trusted') and self.trusted_users:
225 for user in self.configlist('trusted', 'users'):
225 for user in self.configlist('trusted', 'users'):
226 self.trusted_users[user] = 1
226 self.trusted_users[user] = 1
227 for group in self.configlist('trusted', 'groups'):
227 for group in self.configlist('trusted', 'groups'):
228 self.trusted_groups[group] = 1
228 self.trusted_groups[group] = 1
229
229
230 def setconfig(self, section, name, value):
230 def setconfig(self, section, name, value):
231 if not self.overlay:
231 if not self.overlay:
232 self.overlay = util.configparser()
232 self.overlay = util.configparser()
233 for cdata in (self.overlay, self.cdata, self.ucdata):
233 for cdata in (self.overlay, self.cdata, self.ucdata):
234 if not cdata: continue
234 if not cdata: continue
235 if not cdata.has_section(section):
235 if not cdata.has_section(section):
236 cdata.add_section(section)
236 cdata.add_section(section)
237 cdata.set(section, name, value)
237 cdata.set(section, name, value)
238 self.fixconfig(section, name, value)
238 self.fixconfig(section, name, value)
239
239
240 def _get_cdata(self, untrusted):
240 def _get_cdata(self, untrusted):
241 if untrusted and self.ucdata:
241 if untrusted and self.ucdata:
242 return self.ucdata
242 return self.ucdata
243 return self.cdata
243 return self.cdata
244
244
245 def _config(self, section, name, default, funcname, untrusted, abort):
245 def _config(self, section, name, default, funcname, untrusted, abort):
246 cdata = self._get_cdata(untrusted)
246 cdata = self._get_cdata(untrusted)
247 if cdata.has_option(section, name):
247 if cdata.has_option(section, name):
248 try:
248 try:
249 func = getattr(cdata, funcname)
249 func = getattr(cdata, funcname)
250 return func(section, name)
250 return func(section, name)
251 except (ConfigParser.InterpolationError, ValueError), inst:
251 except (ConfigParser.InterpolationError, ValueError), inst:
252 msg = _("Error in configuration section [%s] "
252 msg = _("Error in configuration section [%s] "
253 "parameter '%s':\n%s") % (section, name, inst)
253 "parameter '%s':\n%s") % (section, name, inst)
254 if abort:
254 if abort:
255 raise util.Abort(msg)
255 raise util.Abort(msg)
256 self.warn(_("Ignored: %s\n") % msg)
256 self.warn(_("Ignored: %s\n") % msg)
257 return default
257 return default
258
258
259 def _configcommon(self, section, name, default, funcname, untrusted):
259 def _configcommon(self, section, name, default, funcname, untrusted):
260 value = self._config(section, name, default, funcname,
260 value = self._config(section, name, default, funcname,
261 untrusted, abort=True)
261 untrusted, abort=True)
262 if self.debugflag and not untrusted and self.ucdata:
262 if self.debugflag and not untrusted and self.ucdata:
263 uvalue = self._config(section, name, None, funcname,
263 uvalue = self._config(section, name, None, funcname,
264 untrusted=True, abort=False)
264 untrusted=True, abort=False)
265 if uvalue is not None and uvalue != value:
265 if uvalue is not None and uvalue != value:
266 self.warn(_("Ignoring untrusted configuration option "
266 self.warn(_("Ignoring untrusted configuration option "
267 "%s.%s = %s\n") % (section, name, uvalue))
267 "%s.%s = %s\n") % (section, name, uvalue))
268 return value
268 return value
269
269
270 def config(self, section, name, default=None, untrusted=False):
270 def config(self, section, name, default=None, untrusted=False):
271 return self._configcommon(section, name, default, 'get', untrusted)
271 return self._configcommon(section, name, default, 'get', untrusted)
272
272
273 def configbool(self, section, name, default=False, untrusted=False):
273 def configbool(self, section, name, default=False, untrusted=False):
274 return self._configcommon(section, name, default, 'getboolean',
274 return self._configcommon(section, name, default, 'getboolean',
275 untrusted)
275 untrusted)
276
276
277 def configlist(self, section, name, default=None, untrusted=False):
277 def configlist(self, section, name, default=None, untrusted=False):
278 """Return a list of comma/space separated strings"""
278 """Return a list of comma/space separated strings"""
279 result = self.config(section, name, untrusted=untrusted)
279 result = self.config(section, name, untrusted=untrusted)
280 if result is None:
280 if result is None:
281 result = default or []
281 result = default or []
282 if isinstance(result, basestring):
282 if isinstance(result, basestring):
283 result = result.replace(",", " ").split()
283 result = result.replace(",", " ").split()
284 return result
284 return result
285
285
286 def has_section(self, section, untrusted=False):
286 def has_section(self, section, untrusted=False):
287 '''tell whether section exists in config.'''
287 '''tell whether section exists in config.'''
288 cdata = self._get_cdata(untrusted)
288 cdata = self._get_cdata(untrusted)
289 return cdata.has_section(section)
289 return cdata.has_section(section)
290
290
291 def _configitems(self, section, untrusted, abort):
291 def _configitems(self, section, untrusted, abort):
292 items = {}
292 items = {}
293 cdata = self._get_cdata(untrusted)
293 cdata = self._get_cdata(untrusted)
294 if cdata.has_section(section):
294 if cdata.has_section(section):
295 try:
295 try:
296 items.update(dict(cdata.items(section)))
296 items.update(dict(cdata.items(section)))
297 except ConfigParser.InterpolationError, inst:
297 except ConfigParser.InterpolationError, inst:
298 msg = _("Error in configuration section [%s]:\n"
298 msg = _("Error in configuration section [%s]:\n"
299 "%s") % (section, inst)
299 "%s") % (section, inst)
300 if abort:
300 if abort:
301 raise util.Abort(msg)
301 raise util.Abort(msg)
302 self.warn(_("Ignored: %s\n") % msg)
302 self.warn(_("Ignored: %s\n") % msg)
303 return items
303 return items
304
304
305 def configitems(self, section, untrusted=False):
305 def configitems(self, section, untrusted=False):
306 items = self._configitems(section, untrusted=untrusted, abort=True)
306 items = self._configitems(section, untrusted=untrusted, abort=True)
307 if self.debugflag and not untrusted and self.ucdata:
307 if self.debugflag and not untrusted and self.ucdata:
308 uitems = self._configitems(section, untrusted=True, abort=False)
308 uitems = self._configitems(section, untrusted=True, abort=False)
309 keys = uitems.keys()
309 keys = uitems.keys()
310 keys.sort()
310 keys.sort()
311 for k in keys:
311 for k in keys:
312 if uitems[k] != items.get(k):
312 if uitems[k] != items.get(k):
313 self.warn(_("Ignoring untrusted configuration option "
313 self.warn(_("Ignoring untrusted configuration option "
314 "%s.%s = %s\n") % (section, k, uitems[k]))
314 "%s.%s = %s\n") % (section, k, uitems[k]))
315 x = items.items()
315 x = items.items()
316 x.sort()
316 x.sort()
317 return x
317 return x
318
318
319 def walkconfig(self, untrusted=False):
319 def walkconfig(self, untrusted=False):
320 cdata = self._get_cdata(untrusted)
320 cdata = self._get_cdata(untrusted)
321 sections = cdata.sections()
321 sections = cdata.sections()
322 sections.sort()
322 sections.sort()
323 for section in sections:
323 for section in sections:
324 for name, value in self.configitems(section, untrusted):
324 for name, value in self.configitems(section, untrusted):
325 yield section, name, str(value).replace('\n', '\\n')
325 yield section, name, str(value).replace('\n', '\\n')
326
326
327 def username(self):
327 def username(self):
328 """Return default username to be used in commits.
328 """Return default username to be used in commits.
329
329
330 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
330 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
331 and stop searching if one of these is set.
331 and stop searching if one of these is set.
332 If not found, use ($LOGNAME or $USER or $LNAME or
332 If not found, use ($LOGNAME or $USER or $LNAME or
333 $USERNAME) +"@full.hostname".
333 $USERNAME) +"@full.hostname".
334 """
334 """
335 user = os.environ.get("HGUSER")
335 user = os.environ.get("HGUSER")
336 if user is None:
336 if user is None:
337 user = self.config("ui", "username")
337 user = self.config("ui", "username")
338 if user is None:
338 if user is None:
339 user = os.environ.get("EMAIL")
339 user = os.environ.get("EMAIL")
340 if user is None:
340 if user is None:
341 try:
341 try:
342 user = '%s@%s' % (util.getuser(), socket.getfqdn())
342 user = '%s@%s' % (util.getuser(), socket.getfqdn())
343 self.warn(_("No username found, using '%s' instead\n") % user)
343 self.warn(_("No username found, using '%s' instead\n") % user)
344 except KeyError:
344 except KeyError:
345 pass
345 pass
346 if not user:
346 if not user:
347 raise util.Abort(_("Please specify a username."))
347 raise util.Abort(_("Please specify a username."))
348 return user
348 return user
349
349
350 def shortuser(self, user):
350 def shortuser(self, user):
351 """Return a short representation of a user name or email address."""
351 """Return a short representation of a user name or email address."""
352 if not self.verbose: user = util.shortuser(user)
352 if not self.verbose: user = util.shortuser(user)
353 return user
353 return user
354
354
355 def expandpath(self, loc, default=None):
355 def expandpath(self, loc, default=None):
356 """Return repository location relative to cwd or from [paths]"""
356 """Return repository location relative to cwd or from [paths]"""
357 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
357 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
358 return loc
358 return loc
359
359
360 path = self.config("paths", loc)
360 path = self.config("paths", loc)
361 if not path and default is not None:
361 if not path and default is not None:
362 path = self.config("paths", default)
362 path = self.config("paths", default)
363 return path or loc
363 return path or loc
364
364
365 def pushbuffer(self):
365 def pushbuffer(self):
366 self.buffers.append([])
366 self.buffers.append([])
367
367
368 def popbuffer(self):
368 def popbuffer(self):
369 return "".join(self.buffers.pop())
369 return "".join(self.buffers.pop())
370
370
371 def write(self, *args):
371 def write(self, *args):
372 if self.buffers:
372 if self.buffers:
373 self.buffers[-1].extend([str(a) for a in args])
373 self.buffers[-1].extend([str(a) for a in args])
374 else:
374 else:
375 for a in args:
375 for a in args:
376 sys.stdout.write(str(a))
376 sys.stdout.write(str(a))
377
377
378 def write_err(self, *args):
378 def write_err(self, *args):
379 try:
379 try:
380 if not sys.stdout.closed: sys.stdout.flush()
380 if not sys.stdout.closed: sys.stdout.flush()
381 for a in args:
381 for a in args:
382 sys.stderr.write(str(a))
382 sys.stderr.write(str(a))
383 # stderr may be buffered under win32 when redirected to files,
383 # stderr may be buffered under win32 when redirected to files,
384 # including stdout.
384 # including stdout.
385 if not sys.stderr.closed: sys.stderr.flush()
385 if not sys.stderr.closed: sys.stderr.flush()
386 except IOError, inst:
386 except IOError, inst:
387 if inst.errno != errno.EPIPE:
387 if inst.errno != errno.EPIPE:
388 raise
388 raise
389
389
390 def flush(self):
390 def flush(self):
391 try: sys.stdout.flush()
391 try: sys.stdout.flush()
392 except: pass
392 except: pass
393 try: sys.stderr.flush()
393 try: sys.stderr.flush()
394 except: pass
394 except: pass
395
395
396 def _readline(self, prompt=''):
396 def _readline(self, prompt=''):
397 if self.isatty():
397 if self.isatty():
398 try:
398 try:
399 # magically add command line editing support, where
399 # magically add command line editing support, where
400 # available
400 # available
401 import readline
401 import readline
402 # force demandimport to really load the module
402 # force demandimport to really load the module
403 readline.read_history_file
403 readline.read_history_file
404 except ImportError:
404 except ImportError:
405 pass
405 pass
406 line = raw_input(prompt)
406 line = raw_input(prompt)
407 # When stdin is in binary mode on Windows, it can cause
407 # When stdin is in binary mode on Windows, it can cause
408 # raw_input() to emit an extra trailing carriage return
408 # raw_input() to emit an extra trailing carriage return
409 if os.linesep == '\r\n' and line and line[-1] == '\r':
409 if os.linesep == '\r\n' and line and line[-1] == '\r':
410 line = line[:-1]
410 line = line[:-1]
411 return line
411 return line
412
412
413 def prompt(self, msg, pat=None, default="y", matchflags=0):
413 def prompt(self, msg, pat=None, default="y", matchflags=0):
414 if not self.interactive: return default
414 if not self.interactive: return default
415 while True:
415 while True:
416 try:
416 try:
417 r = self._readline(msg + ' ')
417 r = self._readline(msg + ' ')
418 if not r:
419 return default
418 if not pat or re.match(pat, r, matchflags):
420 if not pat or re.match(pat, r, matchflags):
419 return r
421 return r
420 else:
422 else:
421 self.write(_("unrecognized response\n"))
423 self.write(_("unrecognized response\n"))
422 except EOFError:
424 except EOFError:
423 raise util.Abort(_('response expected'))
425 raise util.Abort(_('response expected'))
424
426
425 def getpass(self, prompt=None, default=None):
427 def getpass(self, prompt=None, default=None):
426 if not self.interactive: return default
428 if not self.interactive: return default
427 return getpass.getpass(prompt or _('password: '))
429 return getpass.getpass(prompt or _('password: '))
428 def status(self, *msg):
430 def status(self, *msg):
429 if not self.quiet: self.write(*msg)
431 if not self.quiet: self.write(*msg)
430 def warn(self, *msg):
432 def warn(self, *msg):
431 self.write_err(*msg)
433 self.write_err(*msg)
432 def note(self, *msg):
434 def note(self, *msg):
433 if self.verbose: self.write(*msg)
435 if self.verbose: self.write(*msg)
434 def debug(self, *msg):
436 def debug(self, *msg):
435 if self.debugflag: self.write(*msg)
437 if self.debugflag: self.write(*msg)
436 def edit(self, text, user):
438 def edit(self, text, user):
437 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
439 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
438 text=True)
440 text=True)
439 try:
441 try:
440 f = os.fdopen(fd, "w")
442 f = os.fdopen(fd, "w")
441 f.write(text)
443 f.write(text)
442 f.close()
444 f.close()
443
445
444 editor = self.geteditor()
446 editor = self.geteditor()
445
447
446 util.system("%s \"%s\"" % (editor, name),
448 util.system("%s \"%s\"" % (editor, name),
447 environ={'HGUSER': user},
449 environ={'HGUSER': user},
448 onerr=util.Abort, errprefix=_("edit failed"))
450 onerr=util.Abort, errprefix=_("edit failed"))
449
451
450 f = open(name)
452 f = open(name)
451 t = f.read()
453 t = f.read()
452 f.close()
454 f.close()
453 t = re.sub("(?m)^HG:.*\n", "", t)
455 t = re.sub("(?m)^HG:.*\n", "", t)
454 finally:
456 finally:
455 os.unlink(name)
457 os.unlink(name)
456
458
457 return t
459 return t
458
460
459 def print_exc(self):
461 def print_exc(self):
460 '''print exception traceback if traceback printing enabled.
462 '''print exception traceback if traceback printing enabled.
461 only to call in exception handler. returns true if traceback
463 only to call in exception handler. returns true if traceback
462 printed.'''
464 printed.'''
463 if self.traceback:
465 if self.traceback:
464 traceback.print_exc()
466 traceback.print_exc()
465 return self.traceback
467 return self.traceback
466
468
467 def geteditor(self):
469 def geteditor(self):
468 '''return editor to use'''
470 '''return editor to use'''
469 return (os.environ.get("HGEDITOR") or
471 return (os.environ.get("HGEDITOR") or
470 self.config("ui", "editor") or
472 self.config("ui", "editor") or
471 os.environ.get("VISUAL") or
473 os.environ.get("VISUAL") or
472 os.environ.get("EDITOR", "vi"))
474 os.environ.get("EDITOR", "vi"))
473
475
General Comments 0
You need to be logged in to leave comments. Login now