##// END OF EJS Templates
Use text rather than binary mode for editing commit messages
Stephen Darnell -
r2206:c74e91e8 default
parent child Browse files
Show More
@@ -1,280 +1,281 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 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 import ConfigParser
8 import ConfigParser
9 from i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "errno os re smtplib socket sys tempfile util")
11 demandload(globals(), "errno os re smtplib socket sys tempfile 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 if parentui is None:
17 if parentui is None:
18 # this is the parent of all ui children
18 # this is the parent of all ui children
19 self.parentui = None
19 self.parentui = None
20 self.cdata = ConfigParser.SafeConfigParser()
20 self.cdata = ConfigParser.SafeConfigParser()
21 self.readconfig(util.rcpath())
21 self.readconfig(util.rcpath())
22
22
23 self.quiet = self.configbool("ui", "quiet")
23 self.quiet = self.configbool("ui", "quiet")
24 self.verbose = self.configbool("ui", "verbose")
24 self.verbose = self.configbool("ui", "verbose")
25 self.debugflag = self.configbool("ui", "debug")
25 self.debugflag = self.configbool("ui", "debug")
26 self.interactive = self.configbool("ui", "interactive", True)
26 self.interactive = self.configbool("ui", "interactive", True)
27 self.traceback = traceback
27 self.traceback = traceback
28
28
29 self.updateopts(verbose, debug, quiet, interactive)
29 self.updateopts(verbose, debug, quiet, interactive)
30 self.diffcache = None
30 self.diffcache = None
31 self.header = []
31 self.header = []
32 self.prev_header = []
32 self.prev_header = []
33 self.revlogopts = self.configrevlog()
33 self.revlogopts = self.configrevlog()
34 else:
34 else:
35 # parentui may point to an ui object which is already a child
35 # parentui may point to an ui object which is already a child
36 self.parentui = parentui.parentui or parentui
36 self.parentui = parentui.parentui or parentui
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):
49 interactive=True, traceback=False):
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
51 self.verbose = (self.verbose or verbose) or debug
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
55
56 def readconfig(self, fn, root=None):
56 def readconfig(self, fn, root=None):
57 if isinstance(fn, basestring):
57 if isinstance(fn, basestring):
58 fn = [fn]
58 fn = [fn]
59 for f in fn:
59 for f in fn:
60 try:
60 try:
61 self.cdata.read(f)
61 self.cdata.read(f)
62 except ConfigParser.ParsingError, inst:
62 except ConfigParser.ParsingError, inst:
63 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
63 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
64 # translate paths relative to root (or home) into absolute paths
64 # translate paths relative to root (or home) into absolute paths
65 if root is None:
65 if root is None:
66 root = os.path.expanduser('~')
66 root = os.path.expanduser('~')
67 for name, path in self.configitems("paths"):
67 for name, path in self.configitems("paths"):
68 if path and path.find("://") == -1 and not os.path.isabs(path):
68 if path and path.find("://") == -1 and not os.path.isabs(path):
69 self.cdata.set("paths", name, os.path.join(root, path))
69 self.cdata.set("paths", name, os.path.join(root, path))
70
70
71 def setconfig(self, section, name, val):
71 def setconfig(self, section, name, val):
72 self.overlay[(section, name)] = val
72 self.overlay[(section, name)] = val
73
73
74 def config(self, section, name, default=None):
74 def config(self, section, name, default=None):
75 if self.overlay.has_key((section, name)):
75 if self.overlay.has_key((section, name)):
76 return self.overlay[(section, name)]
76 return self.overlay[(section, name)]
77 if self.cdata.has_option(section, name):
77 if self.cdata.has_option(section, name):
78 try:
78 try:
79 return self.cdata.get(section, name)
79 return self.cdata.get(section, name)
80 except ConfigParser.InterpolationError, inst:
80 except ConfigParser.InterpolationError, inst:
81 raise util.Abort(_("Error in configuration:\n%s") % inst)
81 raise util.Abort(_("Error in configuration:\n%s") % inst)
82 if self.parentui is None:
82 if self.parentui is None:
83 return default
83 return default
84 else:
84 else:
85 return self.parentui.config(section, name, default)
85 return self.parentui.config(section, name, default)
86
86
87 def configbool(self, section, name, default=False):
87 def configbool(self, section, name, default=False):
88 if self.overlay.has_key((section, name)):
88 if self.overlay.has_key((section, name)):
89 return self.overlay[(section, name)]
89 return self.overlay[(section, name)]
90 if self.cdata.has_option(section, name):
90 if self.cdata.has_option(section, name):
91 try:
91 try:
92 return self.cdata.getboolean(section, name)
92 return self.cdata.getboolean(section, name)
93 except ConfigParser.InterpolationError, inst:
93 except ConfigParser.InterpolationError, inst:
94 raise util.Abort(_("Error in configuration:\n%s") % inst)
94 raise util.Abort(_("Error in configuration:\n%s") % inst)
95 if self.parentui is None:
95 if self.parentui is None:
96 return default
96 return default
97 else:
97 else:
98 return self.parentui.configbool(section, name, default)
98 return self.parentui.configbool(section, name, default)
99
99
100 def configitems(self, section):
100 def configitems(self, section):
101 items = {}
101 items = {}
102 if self.parentui is not None:
102 if self.parentui is not None:
103 items = dict(self.parentui.configitems(section))
103 items = dict(self.parentui.configitems(section))
104 if self.cdata.has_section(section):
104 if self.cdata.has_section(section):
105 try:
105 try:
106 items.update(dict(self.cdata.items(section)))
106 items.update(dict(self.cdata.items(section)))
107 except ConfigParser.InterpolationError, inst:
107 except ConfigParser.InterpolationError, inst:
108 raise util.Abort(_("Error in configuration:\n%s") % inst)
108 raise util.Abort(_("Error in configuration:\n%s") % inst)
109 x = items.items()
109 x = items.items()
110 x.sort()
110 x.sort()
111 return x
111 return x
112
112
113 def walkconfig(self, seen=None):
113 def walkconfig(self, seen=None):
114 if seen is None:
114 if seen is None:
115 seen = {}
115 seen = {}
116 for (section, name), value in self.overlay.iteritems():
116 for (section, name), value in self.overlay.iteritems():
117 yield section, name, value
117 yield section, name, value
118 seen[section, name] = 1
118 seen[section, name] = 1
119 for section in self.cdata.sections():
119 for section in self.cdata.sections():
120 for name, value in self.cdata.items(section):
120 for name, value in self.cdata.items(section):
121 if (section, name) in seen: continue
121 if (section, name) in seen: continue
122 yield section, name, value.replace('\n', '\\n')
122 yield section, name, value.replace('\n', '\\n')
123 seen[section, name] = 1
123 seen[section, name] = 1
124 if self.parentui is not None:
124 if self.parentui is not None:
125 for parent in self.parentui.walkconfig(seen):
125 for parent in self.parentui.walkconfig(seen):
126 yield parent
126 yield parent
127
127
128 def extensions(self):
128 def extensions(self):
129 return self.configitems("extensions")
129 return self.configitems("extensions")
130
130
131 def hgignorefiles(self):
131 def hgignorefiles(self):
132 result = []
132 result = []
133 cfgitems = self.configitems("ui")
133 cfgitems = self.configitems("ui")
134 for key, value in cfgitems:
134 for key, value in cfgitems:
135 if key == 'ignore' or key.startswith('ignore.'):
135 if key == 'ignore' or key.startswith('ignore.'):
136 path = os.path.expanduser(value)
136 path = os.path.expanduser(value)
137 result.append(path)
137 result.append(path)
138 return result
138 return result
139
139
140 def configrevlog(self):
140 def configrevlog(self):
141 ret = {}
141 ret = {}
142 for x in self.configitems("revlog"):
142 for x in self.configitems("revlog"):
143 k = x[0].lower()
143 k = x[0].lower()
144 ret[k] = x[1]
144 ret[k] = x[1]
145 return ret
145 return ret
146 def diffopts(self):
146 def diffopts(self):
147 if self.diffcache:
147 if self.diffcache:
148 return self.diffcache
148 return self.diffcache
149 ret = { 'showfunc' : True, 'ignorews' : False}
149 ret = { 'showfunc' : True, 'ignorews' : False}
150 for x in self.configitems("diff"):
150 for x in self.configitems("diff"):
151 k = x[0].lower()
151 k = x[0].lower()
152 v = x[1]
152 v = x[1]
153 if v:
153 if v:
154 v = v.lower()
154 v = v.lower()
155 if v == 'true':
155 if v == 'true':
156 value = True
156 value = True
157 else:
157 else:
158 value = False
158 value = False
159 ret[k] = value
159 ret[k] = value
160 self.diffcache = ret
160 self.diffcache = ret
161 return ret
161 return ret
162
162
163 def username(self):
163 def username(self):
164 """Return default username to be used in commits.
164 """Return default username to be used in commits.
165
165
166 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
166 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
167 and stop searching if one of these is set.
167 and stop searching if one of these is set.
168 Abort if found username is an empty string to force specifying
168 Abort if found username is an empty string to force specifying
169 the commit user elsewhere, e.g. with line option or repo hgrc.
169 the commit user elsewhere, e.g. with line option or repo hgrc.
170 If not found, use $LOGNAME or $USERNAME +"@full.hostname".
170 If not found, use $LOGNAME or $USERNAME +"@full.hostname".
171 """
171 """
172 user = os.environ.get("HGUSER")
172 user = os.environ.get("HGUSER")
173 if user is None:
173 if user is None:
174 user = self.config("ui", "username")
174 user = self.config("ui", "username")
175 if user is None:
175 if user is None:
176 user = os.environ.get("EMAIL")
176 user = os.environ.get("EMAIL")
177 if user is None:
177 if user is None:
178 user = os.environ.get("LOGNAME") or os.environ.get("USERNAME")
178 user = os.environ.get("LOGNAME") or os.environ.get("USERNAME")
179 if user:
179 if user:
180 user = "%s@%s" % (user, socket.getfqdn())
180 user = "%s@%s" % (user, socket.getfqdn())
181 if not user:
181 if not user:
182 raise util.Abort(_("Please specify a username."))
182 raise util.Abort(_("Please specify a username."))
183 return user
183 return user
184
184
185 def shortuser(self, user):
185 def shortuser(self, user):
186 """Return a short representation of a user name or email address."""
186 """Return a short representation of a user name or email address."""
187 if not self.verbose: user = util.shortuser(user)
187 if not self.verbose: user = util.shortuser(user)
188 return user
188 return user
189
189
190 def expandpath(self, loc):
190 def expandpath(self, loc):
191 """Return repository location relative to cwd or from [paths]"""
191 """Return repository location relative to cwd or from [paths]"""
192 if loc.find("://") != -1 or os.path.exists(loc):
192 if loc.find("://") != -1 or os.path.exists(loc):
193 return loc
193 return loc
194
194
195 return self.config("paths", loc, loc)
195 return self.config("paths", loc, loc)
196
196
197 def write(self, *args):
197 def write(self, *args):
198 if self.header:
198 if self.header:
199 if self.header != self.prev_header:
199 if self.header != self.prev_header:
200 self.prev_header = self.header
200 self.prev_header = self.header
201 self.write(*self.header)
201 self.write(*self.header)
202 self.header = []
202 self.header = []
203 for a in args:
203 for a in args:
204 sys.stdout.write(str(a))
204 sys.stdout.write(str(a))
205
205
206 def write_header(self, *args):
206 def write_header(self, *args):
207 for a in args:
207 for a in args:
208 self.header.append(str(a))
208 self.header.append(str(a))
209
209
210 def write_err(self, *args):
210 def write_err(self, *args):
211 try:
211 try:
212 if not sys.stdout.closed: sys.stdout.flush()
212 if not sys.stdout.closed: sys.stdout.flush()
213 for a in args:
213 for a in args:
214 sys.stderr.write(str(a))
214 sys.stderr.write(str(a))
215 except IOError, inst:
215 except IOError, inst:
216 if inst.errno != errno.EPIPE:
216 if inst.errno != errno.EPIPE:
217 raise
217 raise
218
218
219 def flush(self):
219 def flush(self):
220 try: sys.stdout.flush()
220 try: sys.stdout.flush()
221 except: pass
221 except: pass
222 try: sys.stderr.flush()
222 try: sys.stderr.flush()
223 except: pass
223 except: pass
224
224
225 def readline(self):
225 def readline(self):
226 return sys.stdin.readline()[:-1]
226 return sys.stdin.readline()[:-1]
227 def prompt(self, msg, pat, default="y"):
227 def prompt(self, msg, pat, default="y"):
228 if not self.interactive: return default
228 if not self.interactive: return default
229 while 1:
229 while 1:
230 self.write(msg, " ")
230 self.write(msg, " ")
231 r = self.readline()
231 r = self.readline()
232 if re.match(pat, r):
232 if re.match(pat, r):
233 return r
233 return r
234 else:
234 else:
235 self.write(_("unrecognized response\n"))
235 self.write(_("unrecognized response\n"))
236 def status(self, *msg):
236 def status(self, *msg):
237 if not self.quiet: self.write(*msg)
237 if not self.quiet: self.write(*msg)
238 def warn(self, *msg):
238 def warn(self, *msg):
239 self.write_err(*msg)
239 self.write_err(*msg)
240 def note(self, *msg):
240 def note(self, *msg):
241 if self.verbose: self.write(*msg)
241 if self.verbose: self.write(*msg)
242 def debug(self, *msg):
242 def debug(self, *msg):
243 if self.debugflag: self.write(*msg)
243 if self.debugflag: self.write(*msg)
244 def edit(self, text, user):
244 def edit(self, text, user):
245 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt")
245 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
246 text=True)
246 try:
247 try:
247 f = os.fdopen(fd, "w")
248 f = os.fdopen(fd, "w")
248 f.write(text)
249 f.write(text)
249 f.close()
250 f.close()
250
251
251 editor = (os.environ.get("HGEDITOR") or
252 editor = (os.environ.get("HGEDITOR") or
252 self.config("ui", "editor") or
253 self.config("ui", "editor") or
253 os.environ.get("EDITOR", "vi"))
254 os.environ.get("EDITOR", "vi"))
254
255
255 util.system("%s \"%s\"" % (editor, name),
256 util.system("%s \"%s\"" % (editor, name),
256 environ={'HGUSER': user},
257 environ={'HGUSER': user},
257 onerr=util.Abort, errprefix=_("edit failed"))
258 onerr=util.Abort, errprefix=_("edit failed"))
258
259
259 f = open(name)
260 f = open(name)
260 t = f.read()
261 t = f.read()
261 f.close()
262 f.close()
262 t = re.sub("(?m)^HG:.*\n", "", t)
263 t = re.sub("(?m)^HG:.*\n", "", t)
263 finally:
264 finally:
264 os.unlink(name)
265 os.unlink(name)
265
266
266 return t
267 return t
267
268
268 def sendmail(self):
269 def sendmail(self):
269 s = smtplib.SMTP()
270 s = smtplib.SMTP()
270 s.connect(host = self.config('smtp', 'host', 'mail'),
271 s.connect(host = self.config('smtp', 'host', 'mail'),
271 port = int(self.config('smtp', 'port', 25)))
272 port = int(self.config('smtp', 'port', 25)))
272 if self.configbool('smtp', 'tls'):
273 if self.configbool('smtp', 'tls'):
273 s.ehlo()
274 s.ehlo()
274 s.starttls()
275 s.starttls()
275 s.ehlo()
276 s.ehlo()
276 username = self.config('smtp', 'username')
277 username = self.config('smtp', 'username')
277 password = self.config('smtp', 'password')
278 password = self.config('smtp', 'password')
278 if username and password:
279 if username and password:
279 s.login(username, password)
280 s.login(username, password)
280 return s
281 return s
General Comments 0
You need to be logged in to leave comments. Login now