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