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