##// END OF EJS Templates
ui.py: don't let parent and child ui objects share header and prev_header
Alexis S. L. Carvalho -
r3339:0e3c45a7 default
parent child Browse files
Show More
@@ -1,306 +1,306 b''
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from i18n import gettext as _
9 9 from demandload import *
10 10 demandload(globals(), "errno getpass os re socket sys tempfile")
11 11 demandload(globals(), "ConfigParser mdiff templater traceback util")
12 12
13 13 class ui(object):
14 14 def __init__(self, verbose=False, debug=False, quiet=False,
15 15 interactive=True, traceback=False, parentui=None):
16 16 self.overlay = {}
17 self.header = []
18 self.prev_header = []
17 19 if parentui is None:
18 20 # this is the parent of all ui children
19 21 self.parentui = None
20 22 self.readhooks = []
21 23 self.cdata = ConfigParser.SafeConfigParser()
22 24 self.readconfig(util.rcpath())
23 25
24 26 self.quiet = self.configbool("ui", "quiet")
25 27 self.verbose = self.configbool("ui", "verbose")
26 28 self.debugflag = self.configbool("ui", "debug")
27 29 self.interactive = self.configbool("ui", "interactive", True)
28 30 self.traceback = traceback
29 31
30 32 self.updateopts(verbose, debug, quiet, interactive)
31 33 self.diffcache = None
32 self.header = []
33 self.prev_header = []
34 34 self.revlogopts = self.configrevlog()
35 35 else:
36 36 # parentui may point to an ui object which is already a child
37 37 self.parentui = parentui.parentui or parentui
38 38 self.readhooks = self.parentui.readhooks[:]
39 39 parent_cdata = self.parentui.cdata
40 40 self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
41 41 # make interpolation work
42 42 for section in parent_cdata.sections():
43 43 self.cdata.add_section(section)
44 44 for name, value in parent_cdata.items(section, raw=True):
45 45 self.cdata.set(section, name, value)
46 46
47 47 def __getattr__(self, key):
48 48 return getattr(self.parentui, key)
49 49
50 50 def updateopts(self, verbose=False, debug=False, quiet=False,
51 51 interactive=True, traceback=False, config=[]):
52 52 self.quiet = (self.quiet or quiet) and not verbose and not debug
53 53 self.verbose = ((self.verbose or verbose) or debug) and not self.quiet
54 54 self.debugflag = (self.debugflag or debug)
55 55 self.interactive = (self.interactive and interactive)
56 56 self.traceback = self.traceback or traceback
57 57 for cfg in config:
58 58 try:
59 59 name, value = cfg.split('=', 1)
60 60 section, name = name.split('.', 1)
61 61 if not self.cdata.has_section(section):
62 62 self.cdata.add_section(section)
63 63 if not section or not name:
64 64 raise IndexError
65 65 self.cdata.set(section, name, value)
66 66 except (IndexError, ValueError):
67 67 raise util.Abort(_('malformed --config option: %s') % cfg)
68 68
69 69 def readconfig(self, fn, root=None):
70 70 if isinstance(fn, basestring):
71 71 fn = [fn]
72 72 for f in fn:
73 73 try:
74 74 self.cdata.read(f)
75 75 except ConfigParser.ParsingError, inst:
76 76 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
77 77 # translate paths relative to root (or home) into absolute paths
78 78 if root is None:
79 79 root = os.path.expanduser('~')
80 80 for name, path in self.configitems("paths"):
81 81 if path and "://" not in path and not os.path.isabs(path):
82 82 self.cdata.set("paths", name, os.path.join(root, path))
83 83 for hook in self.readhooks:
84 84 hook(self)
85 85
86 86 def addreadhook(self, hook):
87 87 self.readhooks.append(hook)
88 88
89 89 def setconfig(self, section, name, val):
90 90 self.overlay[(section, name)] = val
91 91
92 92 def config(self, section, name, default=None):
93 93 if self.overlay.has_key((section, name)):
94 94 return self.overlay[(section, name)]
95 95 if self.cdata.has_option(section, name):
96 96 try:
97 97 return self.cdata.get(section, name)
98 98 except ConfigParser.InterpolationError, inst:
99 99 raise util.Abort(_("Error in configuration section [%s] "
100 100 "parameter '%s':\n%s")
101 101 % (section, name, inst))
102 102 if self.parentui is None:
103 103 return default
104 104 else:
105 105 return self.parentui.config(section, name, default)
106 106
107 107 def configlist(self, section, name, default=None):
108 108 """Return a list of comma/space separated strings"""
109 109 result = self.config(section, name)
110 110 if result is None:
111 111 result = default or []
112 112 if isinstance(result, basestring):
113 113 result = result.replace(",", " ").split()
114 114 return result
115 115
116 116 def configbool(self, section, name, default=False):
117 117 if self.overlay.has_key((section, name)):
118 118 return self.overlay[(section, name)]
119 119 if self.cdata.has_option(section, name):
120 120 try:
121 121 return self.cdata.getboolean(section, name)
122 122 except ConfigParser.InterpolationError, inst:
123 123 raise util.Abort(_("Error in configuration section [%s] "
124 124 "parameter '%s':\n%s")
125 125 % (section, name, inst))
126 126 if self.parentui is None:
127 127 return default
128 128 else:
129 129 return self.parentui.configbool(section, name, default)
130 130
131 131 def has_config(self, section):
132 132 '''tell whether section exists in config.'''
133 133 return self.cdata.has_section(section)
134 134
135 135 def configitems(self, section):
136 136 items = {}
137 137 if self.parentui is not None:
138 138 items = dict(self.parentui.configitems(section))
139 139 if self.cdata.has_section(section):
140 140 try:
141 141 items.update(dict(self.cdata.items(section)))
142 142 except ConfigParser.InterpolationError, inst:
143 143 raise util.Abort(_("Error in configuration section [%s]:\n%s")
144 144 % (section, inst))
145 145 x = items.items()
146 146 x.sort()
147 147 return x
148 148
149 149 def walkconfig(self, seen=None):
150 150 if seen is None:
151 151 seen = {}
152 152 for (section, name), value in self.overlay.iteritems():
153 153 yield section, name, value
154 154 seen[section, name] = 1
155 155 for section in self.cdata.sections():
156 156 try:
157 157 for name, value in self.cdata.items(section):
158 158 if (section, name) in seen: continue
159 159 yield section, name, value.replace('\n', '\\n')
160 160 seen[section, name] = 1
161 161 except ConfigParser.InterpolationError, inst:
162 162 raise util.Abort(_("Error in configuration section [%s]:\n%s")
163 163 % (section, inst))
164 164 if self.parentui is not None:
165 165 for parent in self.parentui.walkconfig(seen):
166 166 yield parent
167 167
168 168 def extensions(self):
169 169 result = self.configitems("extensions")
170 170 for i, (key, value) in enumerate(result):
171 171 if value:
172 172 result[i] = (key, os.path.expanduser(value))
173 173 return result
174 174
175 175 def hgignorefiles(self):
176 176 result = []
177 177 for key, value in self.configitems("ui"):
178 178 if key == 'ignore' or key.startswith('ignore.'):
179 179 result.append(os.path.expanduser(value))
180 180 return result
181 181
182 182 def configrevlog(self):
183 183 result = {}
184 184 for key, value in self.configitems("revlog"):
185 185 result[key.lower()] = value
186 186 return result
187 187
188 188 def username(self):
189 189 """Return default username to be used in commits.
190 190
191 191 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
192 192 and stop searching if one of these is set.
193 193 Abort if found username is an empty string to force specifying
194 194 the commit user elsewhere, e.g. with line option or repo hgrc.
195 195 If not found, use ($LOGNAME or $USER or $LNAME or
196 196 $USERNAME) +"@full.hostname".
197 197 """
198 198 user = os.environ.get("HGUSER")
199 199 if user is None:
200 200 user = self.config("ui", "username")
201 201 if user is None:
202 202 user = os.environ.get("EMAIL")
203 203 if user is None:
204 204 try:
205 205 user = '%s@%s' % (util.getuser(), socket.getfqdn())
206 206 except KeyError:
207 207 raise util.Abort(_("Please specify a username."))
208 208 return user
209 209
210 210 def shortuser(self, user):
211 211 """Return a short representation of a user name or email address."""
212 212 if not self.verbose: user = util.shortuser(user)
213 213 return user
214 214
215 215 def expandpath(self, loc, default=None):
216 216 """Return repository location relative to cwd or from [paths]"""
217 217 if "://" in loc or os.path.isdir(loc):
218 218 return loc
219 219
220 220 path = self.config("paths", loc)
221 221 if not path and default is not None:
222 222 path = self.config("paths", default)
223 223 return path or loc
224 224
225 225 def write(self, *args):
226 226 if self.header:
227 227 if self.header != self.prev_header:
228 228 self.prev_header = self.header
229 229 self.write(*self.header)
230 230 self.header = []
231 231 for a in args:
232 232 sys.stdout.write(str(a))
233 233
234 234 def write_header(self, *args):
235 235 for a in args:
236 236 self.header.append(str(a))
237 237
238 238 def write_err(self, *args):
239 239 try:
240 240 if not sys.stdout.closed: sys.stdout.flush()
241 241 for a in args:
242 242 sys.stderr.write(str(a))
243 243 except IOError, inst:
244 244 if inst.errno != errno.EPIPE:
245 245 raise
246 246
247 247 def flush(self):
248 248 try: sys.stdout.flush()
249 249 except: pass
250 250 try: sys.stderr.flush()
251 251 except: pass
252 252
253 253 def readline(self):
254 254 return sys.stdin.readline()[:-1]
255 255 def prompt(self, msg, pat=None, default="y"):
256 256 if not self.interactive: return default
257 257 while 1:
258 258 self.write(msg, " ")
259 259 r = self.readline()
260 260 if not pat or re.match(pat, r):
261 261 return r
262 262 else:
263 263 self.write(_("unrecognized response\n"))
264 264 def getpass(self, prompt=None, default=None):
265 265 if not self.interactive: return default
266 266 return getpass.getpass(prompt or _('password: '))
267 267 def status(self, *msg):
268 268 if not self.quiet: self.write(*msg)
269 269 def warn(self, *msg):
270 270 self.write_err(*msg)
271 271 def note(self, *msg):
272 272 if self.verbose: self.write(*msg)
273 273 def debug(self, *msg):
274 274 if self.debugflag: self.write(*msg)
275 275 def edit(self, text, user):
276 276 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
277 277 text=True)
278 278 try:
279 279 f = os.fdopen(fd, "w")
280 280 f.write(text)
281 281 f.close()
282 282
283 283 editor = (os.environ.get("HGEDITOR") or
284 284 self.config("ui", "editor") or
285 285 os.environ.get("EDITOR", "vi"))
286 286
287 287 util.system("%s \"%s\"" % (editor, name),
288 288 environ={'HGUSER': user},
289 289 onerr=util.Abort, errprefix=_("edit failed"))
290 290
291 291 f = open(name)
292 292 t = f.read()
293 293 f.close()
294 294 t = re.sub("(?m)^HG:.*\n", "", t)
295 295 finally:
296 296 os.unlink(name)
297 297
298 298 return t
299 299
300 300 def print_exc(self):
301 301 '''print exception traceback if traceback printing enabled.
302 302 only to call in exception handler. returns true if traceback
303 303 printed.'''
304 304 if self.traceback:
305 305 traceback.print_exc()
306 306 return self.traceback
General Comments 0
You need to be logged in to leave comments. Login now