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