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