##// END OF EJS Templates
prompt user for http authentication info...
Vadim Gelfer -
r2281:7761597b default
parent child Browse files
Show More
@@ -1,142 +1,169 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httprepo.py - HTTP repository proxy classes 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 from node import *
8 from node import *
9 from remoterepo import *
9 from remoterepo import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 from demandload import *
11 from demandload import *
12 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
12 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
13
13
14 class passwordmgr(urllib2.HTTPPasswordMgr):
15 def __init__(self, ui):
16 urllib2.HTTPPasswordMgr.__init__(self)
17 self.ui = ui
18
19 def find_user_password(self, realm, authuri):
20 authinfo = urllib2.HTTPPasswordMgr.find_user_password(
21 self, realm, authuri)
22 if authinfo != (None, None):
23 return authinfo
24
25 self.ui.write(_("http authorization required\n"))
26 self.ui.status(_("realm: %s\n") % realm)
27 user = self.ui.prompt(_("user:"), default=None)
28 passwd = self.ui.getpass()
29
30 self.add_password(realm, authuri, user, passwd)
31 return (user, passwd)
32
14 class httprepository(remoterepository):
33 class httprepository(remoterepository):
15 def __init__(self, ui, path):
34 def __init__(self, ui, path):
16 # fix missing / after hostname
35 # fix missing / after hostname
17 s = urlparse.urlsplit(path)
36 s = urlparse.urlsplit(path)
18 partial = s[2]
37 partial = s[2]
19 if not partial: partial = "/"
38 if not partial: partial = "/"
20 self.url = urlparse.urlunsplit((s[0], s[1], partial, '', ''))
39 self.url = urlparse.urlunsplit((s[0], s[1], partial, '', ''))
21 self.ui = ui
40 self.ui = ui
22 no_list = [ "localhost", "127.0.0.1" ]
41 no_list = [ "localhost", "127.0.0.1" ]
23 host = ui.config("http_proxy", "host")
42 host = ui.config("http_proxy", "host")
24 if host is None:
43 if host is None:
25 host = os.environ.get("http_proxy")
44 host = os.environ.get("http_proxy")
26 if host and host.startswith('http://'):
45 if host and host.startswith('http://'):
27 host = host[7:]
46 host = host[7:]
28 user = ui.config("http_proxy", "user")
47 user = ui.config("http_proxy", "user")
29 passwd = ui.config("http_proxy", "passwd")
48 passwd = ui.config("http_proxy", "passwd")
30 no = ui.config("http_proxy", "no")
49 no = ui.config("http_proxy", "no")
31 if no is None:
50 if no is None:
32 no = os.environ.get("no_proxy")
51 no = os.environ.get("no_proxy")
33 if no:
52 if no:
34 no_list = no_list + no.split(",")
53 no_list = no_list + no.split(",")
35
54
36 no_proxy = 0
55 no_proxy = 0
37 for h in no_list:
56 for h in no_list:
38 if (path.startswith("http://" + h + "/") or
57 if (path.startswith("http://" + h + "/") or
39 path.startswith("http://" + h + ":") or
58 path.startswith("http://" + h + ":") or
40 path == "http://" + h):
59 path == "http://" + h):
41 no_proxy = 1
60 no_proxy = 1
42
61
43 # Note: urllib2 takes proxy values from the environment and those will
62 # Note: urllib2 takes proxy values from the environment and those will
44 # take precedence
63 # take precedence
45 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
64 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
46 try:
65 try:
47 if os.environ.has_key(env):
66 if os.environ.has_key(env):
48 del os.environ[env]
67 del os.environ[env]
49 except OSError:
68 except OSError:
50 pass
69 pass
51
70
52 proxy_handler = urllib2.BaseHandler()
71 proxy_handler = urllib2.BaseHandler()
53 if host and not no_proxy:
72 if host and not no_proxy:
54 proxy_handler = urllib2.ProxyHandler({"http" : "http://" + host})
73 proxy_handler = urllib2.ProxyHandler({"http" : "http://" + host})
55
74
56 authinfo = None
75 proxyauthinfo = None
57 if user and passwd:
76 if user and passwd:
58 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
77 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
59 passmgr.add_password(None, host, user, passwd)
78 passmgr.add_password(None, host, user, passwd)
60 authinfo = urllib2.ProxyBasicAuthHandler(passmgr)
79 proxyauthinfo = urllib2.ProxyBasicAuthHandler(passmgr)
61
80
62 opener = urllib2.build_opener(proxy_handler, authinfo)
81 if ui.interactive:
82 passmgr = passwordmgr(ui)
83 opener = urllib2.build_opener(
84 proxy_handler, proxyauthinfo,
85 urllib2.HTTPBasicAuthHandler(passmgr),
86 urllib2.HTTPDigestAuthHandler(passmgr))
87 else:
88 opener = urllib2.build_opener(proxy_handler, proxyauthinfo)
89
63 # 1.0 here is the _protocol_ version
90 # 1.0 here is the _protocol_ version
64 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
91 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
65 urllib2.install_opener(opener)
92 urllib2.install_opener(opener)
66
93
67 def dev(self):
94 def dev(self):
68 return -1
95 return -1
69
96
70 def lock(self):
97 def lock(self):
71 raise util.Abort(_('operation not supported over http'))
98 raise util.Abort(_('operation not supported over http'))
72
99
73 def do_cmd(self, cmd, **args):
100 def do_cmd(self, cmd, **args):
74 self.ui.debug(_("sending %s command\n") % cmd)
101 self.ui.debug(_("sending %s command\n") % cmd)
75 q = {"cmd": cmd}
102 q = {"cmd": cmd}
76 q.update(args)
103 q.update(args)
77 qs = urllib.urlencode(q)
104 qs = urllib.urlencode(q)
78 cu = "%s?%s" % (self.url, qs)
105 cu = "%s?%s" % (self.url, qs)
79 resp = urllib2.urlopen(cu)
106 resp = urllib2.urlopen(cu)
80 proto = resp.headers['content-type']
107 proto = resp.headers['content-type']
81
108
82 # accept old "text/plain" and "application/hg-changegroup" for now
109 # accept old "text/plain" and "application/hg-changegroup" for now
83 if not proto.startswith('application/mercurial') and \
110 if not proto.startswith('application/mercurial') and \
84 not proto.startswith('text/plain') and \
111 not proto.startswith('text/plain') and \
85 not proto.startswith('application/hg-changegroup'):
112 not proto.startswith('application/hg-changegroup'):
86 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
113 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
87 self.url)
114 self.url)
88
115
89 if proto.startswith('application/mercurial'):
116 if proto.startswith('application/mercurial'):
90 version = proto[22:]
117 version = proto[22:]
91 if float(version) > 0.1:
118 if float(version) > 0.1:
92 raise hg.RepoError(_("'%s' uses newer protocol %s") %
119 raise hg.RepoError(_("'%s' uses newer protocol %s") %
93 (self.url, version))
120 (self.url, version))
94
121
95 return resp
122 return resp
96
123
97 def heads(self):
124 def heads(self):
98 d = self.do_cmd("heads").read()
125 d = self.do_cmd("heads").read()
99 try:
126 try:
100 return map(bin, d[:-1].split(" "))
127 return map(bin, d[:-1].split(" "))
101 except:
128 except:
102 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
129 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
103 raise
130 raise
104
131
105 def branches(self, nodes):
132 def branches(self, nodes):
106 n = " ".join(map(hex, nodes))
133 n = " ".join(map(hex, nodes))
107 d = self.do_cmd("branches", nodes=n).read()
134 d = self.do_cmd("branches", nodes=n).read()
108 try:
135 try:
109 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
136 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
110 return br
137 return br
111 except:
138 except:
112 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
139 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
113 raise
140 raise
114
141
115 def between(self, pairs):
142 def between(self, pairs):
116 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
143 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
117 d = self.do_cmd("between", pairs=n).read()
144 d = self.do_cmd("between", pairs=n).read()
118 try:
145 try:
119 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
146 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
120 return p
147 return p
121 except:
148 except:
122 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
149 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
123 raise
150 raise
124
151
125 def changegroup(self, nodes, kind):
152 def changegroup(self, nodes, kind):
126 n = " ".join(map(hex, nodes))
153 n = " ".join(map(hex, nodes))
127 f = self.do_cmd("changegroup", roots=n)
154 f = self.do_cmd("changegroup", roots=n)
128 bytes = 0
155 bytes = 0
129
156
130 def zgenerator(f):
157 def zgenerator(f):
131 zd = zlib.decompressobj()
158 zd = zlib.decompressobj()
132 try:
159 try:
133 for chnk in f:
160 for chnk in f:
134 yield zd.decompress(chnk)
161 yield zd.decompress(chnk)
135 except httplib.HTTPException, inst:
162 except httplib.HTTPException, inst:
136 raise IOError(None, _('connection ended unexpectedly'))
163 raise IOError(None, _('connection ended unexpectedly'))
137 yield zd.flush()
164 yield zd.flush()
138
165
139 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
166 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
140
167
141 class httpsrepository(httprepository):
168 class httpsrepository(httprepository):
142 pass
169 pass
@@ -1,281 +1,284 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 getpass 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=None, 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 not pat or 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 getpass(self, prompt=None, default=None):
237 if not self.interactive: return default
238 return getpass.getpass(prompt or _('password: '))
236 def status(self, *msg):
239 def status(self, *msg):
237 if not self.quiet: self.write(*msg)
240 if not self.quiet: self.write(*msg)
238 def warn(self, *msg):
241 def warn(self, *msg):
239 self.write_err(*msg)
242 self.write_err(*msg)
240 def note(self, *msg):
243 def note(self, *msg):
241 if self.verbose: self.write(*msg)
244 if self.verbose: self.write(*msg)
242 def debug(self, *msg):
245 def debug(self, *msg):
243 if self.debugflag: self.write(*msg)
246 if self.debugflag: self.write(*msg)
244 def edit(self, text, user):
247 def edit(self, text, user):
245 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
248 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
246 text=True)
249 text=True)
247 try:
250 try:
248 f = os.fdopen(fd, "w")
251 f = os.fdopen(fd, "w")
249 f.write(text)
252 f.write(text)
250 f.close()
253 f.close()
251
254
252 editor = (os.environ.get("HGEDITOR") or
255 editor = (os.environ.get("HGEDITOR") or
253 self.config("ui", "editor") or
256 self.config("ui", "editor") or
254 os.environ.get("EDITOR", "vi"))
257 os.environ.get("EDITOR", "vi"))
255
258
256 util.system("%s \"%s\"" % (editor, name),
259 util.system("%s \"%s\"" % (editor, name),
257 environ={'HGUSER': user},
260 environ={'HGUSER': user},
258 onerr=util.Abort, errprefix=_("edit failed"))
261 onerr=util.Abort, errprefix=_("edit failed"))
259
262
260 f = open(name)
263 f = open(name)
261 t = f.read()
264 t = f.read()
262 f.close()
265 f.close()
263 t = re.sub("(?m)^HG:.*\n", "", t)
266 t = re.sub("(?m)^HG:.*\n", "", t)
264 finally:
267 finally:
265 os.unlink(name)
268 os.unlink(name)
266
269
267 return t
270 return t
268
271
269 def sendmail(self):
272 def sendmail(self):
270 s = smtplib.SMTP()
273 s = smtplib.SMTP()
271 s.connect(host = self.config('smtp', 'host', 'mail'),
274 s.connect(host = self.config('smtp', 'host', 'mail'),
272 port = int(self.config('smtp', 'port', 25)))
275 port = int(self.config('smtp', 'port', 25)))
273 if self.configbool('smtp', 'tls'):
276 if self.configbool('smtp', 'tls'):
274 s.ehlo()
277 s.ehlo()
275 s.starttls()
278 s.starttls()
276 s.ehlo()
279 s.ehlo()
277 username = self.config('smtp', 'username')
280 username = self.config('smtp', 'username')
278 password = self.config('smtp', 'password')
281 password = self.config('smtp', 'password')
279 if username and password:
282 if username and password:
280 s.login(username, password)
283 s.login(username, password)
281 return s
284 return s
General Comments 0
You need to be logged in to leave comments. Login now