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