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