##// END OF EJS Templates
ui.py: move common code out of config and configbool
Alexis S. L. Carvalho -
r3341:a7cec14c default
parent child Browse files
Show More
@@ -1,304 +1,296
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 def config(self, section, name, default=None):
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 return self.cdata.get(section, name)
95 func = getattr(self.cdata, funcname)
96 return func(section, name)
96 97 except ConfigParser.InterpolationError, inst:
97 98 raise util.Abort(_("Error in configuration section [%s] "
98 99 "parameter '%s':\n%s")
99 100 % (section, name, inst))
100 101 if self.parentui is None:
101 102 return default
102 103 else:
103 return self.parentui.config(section, name, default)
104 return self.parentui._config(section, name, default, funcname)
105
106 def config(self, section, name, default=None):
107 return self._config(section, name, default, 'get')
108
109 def configbool(self, section, name, default=False):
110 return self._config(section, name, default, 'getboolean')
104 111
105 112 def configlist(self, section, name, default=None):
106 113 """Return a list of comma/space separated strings"""
107 114 result = self.config(section, name)
108 115 if result is None:
109 116 result = default or []
110 117 if isinstance(result, basestring):
111 118 result = result.replace(",", " ").split()
112 119 return result
113 120
114 def configbool(self, section, name, default=False):
115 if self.overlay.has_key((section, name)):
116 return self.overlay[(section, name)]
117 if self.cdata.has_option(section, name):
118 try:
119 return self.cdata.getboolean(section, name)
120 except ConfigParser.InterpolationError, inst:
121 raise util.Abort(_("Error in configuration section [%s] "
122 "parameter '%s':\n%s")
123 % (section, name, inst))
124 if self.parentui is None:
125 return default
126 else:
127 return self.parentui.configbool(section, name, default)
128
129 121 def has_config(self, section):
130 122 '''tell whether section exists in config.'''
131 123 return self.cdata.has_section(section)
132 124
133 125 def configitems(self, section):
134 126 items = {}
135 127 if self.parentui is not None:
136 128 items = dict(self.parentui.configitems(section))
137 129 if self.cdata.has_section(section):
138 130 try:
139 131 items.update(dict(self.cdata.items(section)))
140 132 except ConfigParser.InterpolationError, inst:
141 133 raise util.Abort(_("Error in configuration section [%s]:\n%s")
142 134 % (section, inst))
143 135 x = items.items()
144 136 x.sort()
145 137 return x
146 138
147 139 def walkconfig(self, seen=None):
148 140 if seen is None:
149 141 seen = {}
150 142 for (section, name), value in self.overlay.iteritems():
151 143 yield section, name, value
152 144 seen[section, name] = 1
153 145 for section in self.cdata.sections():
154 146 try:
155 147 for name, value in self.cdata.items(section):
156 148 if (section, name) in seen: continue
157 149 yield section, name, value.replace('\n', '\\n')
158 150 seen[section, name] = 1
159 151 except ConfigParser.InterpolationError, inst:
160 152 raise util.Abort(_("Error in configuration section [%s]:\n%s")
161 153 % (section, inst))
162 154 if self.parentui is not None:
163 155 for parent in self.parentui.walkconfig(seen):
164 156 yield parent
165 157
166 158 def extensions(self):
167 159 result = self.configitems("extensions")
168 160 for i, (key, value) in enumerate(result):
169 161 if value:
170 162 result[i] = (key, os.path.expanduser(value))
171 163 return result
172 164
173 165 def hgignorefiles(self):
174 166 result = []
175 167 for key, value in self.configitems("ui"):
176 168 if key == 'ignore' or key.startswith('ignore.'):
177 169 result.append(os.path.expanduser(value))
178 170 return result
179 171
180 172 def configrevlog(self):
181 173 result = {}
182 174 for key, value in self.configitems("revlog"):
183 175 result[key.lower()] = value
184 176 return result
185 177
186 178 def username(self):
187 179 """Return default username to be used in commits.
188 180
189 181 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
190 182 and stop searching if one of these is set.
191 183 Abort if found username is an empty string to force specifying
192 184 the commit user elsewhere, e.g. with line option or repo hgrc.
193 185 If not found, use ($LOGNAME or $USER or $LNAME or
194 186 $USERNAME) +"@full.hostname".
195 187 """
196 188 user = os.environ.get("HGUSER")
197 189 if user is None:
198 190 user = self.config("ui", "username")
199 191 if user is None:
200 192 user = os.environ.get("EMAIL")
201 193 if user is None:
202 194 try:
203 195 user = '%s@%s' % (util.getuser(), socket.getfqdn())
204 196 except KeyError:
205 197 raise util.Abort(_("Please specify a username."))
206 198 return user
207 199
208 200 def shortuser(self, user):
209 201 """Return a short representation of a user name or email address."""
210 202 if not self.verbose: user = util.shortuser(user)
211 203 return user
212 204
213 205 def expandpath(self, loc, default=None):
214 206 """Return repository location relative to cwd or from [paths]"""
215 207 if "://" in loc or os.path.isdir(loc):
216 208 return loc
217 209
218 210 path = self.config("paths", loc)
219 211 if not path and default is not None:
220 212 path = self.config("paths", default)
221 213 return path or loc
222 214
223 215 def write(self, *args):
224 216 if self.header:
225 217 if self.header != self.prev_header:
226 218 self.prev_header = self.header
227 219 self.write(*self.header)
228 220 self.header = []
229 221 for a in args:
230 222 sys.stdout.write(str(a))
231 223
232 224 def write_header(self, *args):
233 225 for a in args:
234 226 self.header.append(str(a))
235 227
236 228 def write_err(self, *args):
237 229 try:
238 230 if not sys.stdout.closed: sys.stdout.flush()
239 231 for a in args:
240 232 sys.stderr.write(str(a))
241 233 except IOError, inst:
242 234 if inst.errno != errno.EPIPE:
243 235 raise
244 236
245 237 def flush(self):
246 238 try: sys.stdout.flush()
247 239 except: pass
248 240 try: sys.stderr.flush()
249 241 except: pass
250 242
251 243 def readline(self):
252 244 return sys.stdin.readline()[:-1]
253 245 def prompt(self, msg, pat=None, default="y"):
254 246 if not self.interactive: return default
255 247 while 1:
256 248 self.write(msg, " ")
257 249 r = self.readline()
258 250 if not pat or re.match(pat, r):
259 251 return r
260 252 else:
261 253 self.write(_("unrecognized response\n"))
262 254 def getpass(self, prompt=None, default=None):
263 255 if not self.interactive: return default
264 256 return getpass.getpass(prompt or _('password: '))
265 257 def status(self, *msg):
266 258 if not self.quiet: self.write(*msg)
267 259 def warn(self, *msg):
268 260 self.write_err(*msg)
269 261 def note(self, *msg):
270 262 if self.verbose: self.write(*msg)
271 263 def debug(self, *msg):
272 264 if self.debugflag: self.write(*msg)
273 265 def edit(self, text, user):
274 266 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
275 267 text=True)
276 268 try:
277 269 f = os.fdopen(fd, "w")
278 270 f.write(text)
279 271 f.close()
280 272
281 273 editor = (os.environ.get("HGEDITOR") or
282 274 self.config("ui", "editor") or
283 275 os.environ.get("EDITOR", "vi"))
284 276
285 277 util.system("%s \"%s\"" % (editor, name),
286 278 environ={'HGUSER': user},
287 279 onerr=util.Abort, errprefix=_("edit failed"))
288 280
289 281 f = open(name)
290 282 t = f.read()
291 283 f.close()
292 284 t = re.sub("(?m)^HG:.*\n", "", t)
293 285 finally:
294 286 os.unlink(name)
295 287
296 288 return t
297 289
298 290 def print_exc(self):
299 291 '''print exception traceback if traceback printing enabled.
300 292 only to call in exception handler. returns true if traceback
301 293 printed.'''
302 294 if self.traceback:
303 295 traceback.print_exc()
304 296 return self.traceback
General Comments 0
You need to be logged in to leave comments. Login now