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