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