Mercurial > traipse_dev
comparison upmana/mercurial/httprepo.py @ 135:dcf4fbe09b70 beta
Traipse Beta 'OpenRPG' {091010-00}
Traipse is a distribution of OpenRPG that is designed to be easy to setup and go. Traipse also makes it easy for developers to work on
code without fear of sacrifice. 'Ornery-Orc' continues the trend of 'Grumpy' and adds fixes to the code. 'Ornery-Orc's main goal is to
offer more advanced features and enhance the productivity of the user.
Update Summary (Beta)
Added Bookmarks
Fix to Remote Admin Commands
Minor fix to text based Server
Fix to Pretty Print, from Core
Fix to Splitter Nodes not being created
Fix to massive amounts of images loading, from Core
Added 'boot' command to remote admin
Added confirmation window for sent nodes
Minor changes to allow for portability to an OpenSUSE linux OS
Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG
Zoom Mouse plugin added
Images added to Plugin UI
Switching to Element Tree
Map efficiency, from FlexiRPG
Added Status Bar to Update Manager
default_manifest.xml renamed to default_upmana.xml
Cleaner clode for saved repositories
New TrueDebug Class in orpg_log (See documentation for usage)
Mercurial's hgweb folder is ported to upmana
**Pretty important update that can help remove thousands of dead children from your gametree.
**Children, <forms />, <group_atts />, <horizontal />, <cols />, <rows />, <height />, etc... are all tags now. Check your gametree and
look for dead children!!
**New Gamtree Recusion method, mapping, and context sensitivity. !!Alpha - Watch out for infinite loops!!
author | sirebral |
---|---|
date | Tue, 10 Nov 2009 14:11:28 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
101:394ebb3b6a0f | 135:dcf4fbe09b70 |
---|---|
1 # httprepo.py - HTTP repository proxy classes for mercurial | |
2 # | |
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | |
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |
5 # | |
6 # This software may be used and distributed according to the terms of the | |
7 # GNU General Public License version 2, incorporated herein by reference. | |
8 | |
9 from node import bin, hex, nullid | |
10 from i18n import _ | |
11 import repo, changegroup, statichttprepo, error, url, util | |
12 import os, urllib, urllib2, urlparse, zlib, httplib | |
13 import errno, socket | |
14 | |
15 def zgenerator(f): | |
16 zd = zlib.decompressobj() | |
17 try: | |
18 for chunk in util.filechunkiter(f): | |
19 yield zd.decompress(chunk) | |
20 except httplib.HTTPException: | |
21 raise IOError(None, _('connection ended unexpectedly')) | |
22 yield zd.flush() | |
23 | |
24 class httprepository(repo.repository): | |
25 def __init__(self, ui, path): | |
26 self.path = path | |
27 self.caps = None | |
28 self.handler = None | |
29 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path) | |
30 if query or frag: | |
31 raise util.Abort(_('unsupported URL component: "%s"') % | |
32 (query or frag)) | |
33 | |
34 # urllib cannot handle URLs with embedded user or passwd | |
35 self._url, authinfo = url.getauthinfo(path) | |
36 | |
37 self.ui = ui | |
38 self.ui.debug(_('using %s\n') % self._url) | |
39 | |
40 self.urlopener = url.opener(ui, authinfo) | |
41 | |
42 def __del__(self): | |
43 for h in self.urlopener.handlers: | |
44 h.close() | |
45 if hasattr(h, "close_all"): | |
46 h.close_all() | |
47 | |
48 def url(self): | |
49 return self.path | |
50 | |
51 # look up capabilities only when needed | |
52 | |
53 def get_caps(self): | |
54 if self.caps is None: | |
55 try: | |
56 self.caps = set(self.do_read('capabilities').split()) | |
57 except error.RepoError: | |
58 self.caps = set() | |
59 self.ui.debug(_('capabilities: %s\n') % | |
60 (' '.join(self.caps or ['none']))) | |
61 return self.caps | |
62 | |
63 capabilities = property(get_caps) | |
64 | |
65 def lock(self): | |
66 raise util.Abort(_('operation not supported over http')) | |
67 | |
68 def do_cmd(self, cmd, **args): | |
69 data = args.pop('data', None) | |
70 headers = args.pop('headers', {}) | |
71 self.ui.debug(_("sending %s command\n") % cmd) | |
72 q = {"cmd": cmd} | |
73 q.update(args) | |
74 qs = '?%s' % urllib.urlencode(q) | |
75 cu = "%s%s" % (self._url, qs) | |
76 try: | |
77 if data: | |
78 self.ui.debug(_("sending %s bytes\n") % len(data)) | |
79 resp = self.urlopener.open(urllib2.Request(cu, data, headers)) | |
80 except urllib2.HTTPError, inst: | |
81 if inst.code == 401: | |
82 raise util.Abort(_('authorization failed')) | |
83 raise | |
84 except httplib.HTTPException, inst: | |
85 self.ui.debug(_('http error while sending %s command\n') % cmd) | |
86 self.ui.traceback() | |
87 raise IOError(None, inst) | |
88 except IndexError: | |
89 # this only happens with Python 2.3, later versions raise URLError | |
90 raise util.Abort(_('http error, possibly caused by proxy setting')) | |
91 # record the url we got redirected to | |
92 resp_url = resp.geturl() | |
93 if resp_url.endswith(qs): | |
94 resp_url = resp_url[:-len(qs)] | |
95 if self._url != resp_url: | |
96 self.ui.status(_('real URL is %s\n') % resp_url) | |
97 self._url = resp_url | |
98 try: | |
99 proto = resp.getheader('content-type') | |
100 except AttributeError: | |
101 proto = resp.headers['content-type'] | |
102 | |
103 safeurl = url.hidepassword(self._url) | |
104 # accept old "text/plain" and "application/hg-changegroup" for now | |
105 if not (proto.startswith('application/mercurial-') or | |
106 proto.startswith('text/plain') or | |
107 proto.startswith('application/hg-changegroup')): | |
108 self.ui.debug(_("requested URL: '%s'\n") % url.hidepassword(cu)) | |
109 raise error.RepoError(_("'%s' does not appear to be an hg repository") | |
110 % safeurl) | |
111 | |
112 if proto.startswith('application/mercurial-'): | |
113 try: | |
114 version = proto.split('-', 1)[1] | |
115 version_info = tuple([int(n) for n in version.split('.')]) | |
116 except ValueError: | |
117 raise error.RepoError(_("'%s' sent a broken Content-Type " | |
118 "header (%s)") % (safeurl, proto)) | |
119 if version_info > (0, 1): | |
120 raise error.RepoError(_("'%s' uses newer protocol %s") % | |
121 (safeurl, version)) | |
122 | |
123 return resp | |
124 | |
125 def do_read(self, cmd, **args): | |
126 fp = self.do_cmd(cmd, **args) | |
127 try: | |
128 return fp.read() | |
129 finally: | |
130 # if using keepalive, allow connection to be reused | |
131 fp.close() | |
132 | |
133 def lookup(self, key): | |
134 self.requirecap('lookup', _('look up remote revision')) | |
135 d = self.do_cmd("lookup", key = key).read() | |
136 success, data = d[:-1].split(' ', 1) | |
137 if int(success): | |
138 return bin(data) | |
139 raise error.RepoError(data) | |
140 | |
141 def heads(self): | |
142 d = self.do_read("heads") | |
143 try: | |
144 return map(bin, d[:-1].split(" ")) | |
145 except: | |
146 raise error.ResponseError(_("unexpected response:"), d) | |
147 | |
148 def branchmap(self): | |
149 d = self.do_read("branchmap") | |
150 try: | |
151 branchmap = {} | |
152 for branchpart in d.splitlines(): | |
153 branchheads = branchpart.split(' ') | |
154 branchname = urllib.unquote(branchheads[0]) | |
155 branchheads = [bin(x) for x in branchheads[1:]] | |
156 branchmap[branchname] = branchheads | |
157 return branchmap | |
158 except: | |
159 raise error.ResponseError(_("unexpected response:"), d) | |
160 | |
161 def branches(self, nodes): | |
162 n = " ".join(map(hex, nodes)) | |
163 d = self.do_read("branches", nodes=n) | |
164 try: | |
165 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ] | |
166 return br | |
167 except: | |
168 raise error.ResponseError(_("unexpected response:"), d) | |
169 | |
170 def between(self, pairs): | |
171 batch = 8 # avoid giant requests | |
172 r = [] | |
173 for i in xrange(0, len(pairs), batch): | |
174 n = " ".join(["-".join(map(hex, p)) for p in pairs[i:i + batch]]) | |
175 d = self.do_read("between", pairs=n) | |
176 try: | |
177 r += [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ] | |
178 except: | |
179 raise error.ResponseError(_("unexpected response:"), d) | |
180 return r | |
181 | |
182 def changegroup(self, nodes, kind): | |
183 n = " ".join(map(hex, nodes)) | |
184 f = self.do_cmd("changegroup", roots=n) | |
185 return util.chunkbuffer(zgenerator(f)) | |
186 | |
187 def changegroupsubset(self, bases, heads, source): | |
188 self.requirecap('changegroupsubset', _('look up remote changes')) | |
189 baselst = " ".join([hex(n) for n in bases]) | |
190 headlst = " ".join([hex(n) for n in heads]) | |
191 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst) | |
192 return util.chunkbuffer(zgenerator(f)) | |
193 | |
194 def unbundle(self, cg, heads, source): | |
195 # have to stream bundle to a temp file because we do not have | |
196 # http 1.1 chunked transfer. | |
197 | |
198 type = "" | |
199 types = self.capable('unbundle') | |
200 # servers older than d1b16a746db6 will send 'unbundle' as a | |
201 # boolean capability | |
202 try: | |
203 types = types.split(',') | |
204 except AttributeError: | |
205 types = [""] | |
206 if types: | |
207 for x in types: | |
208 if x in changegroup.bundletypes: | |
209 type = x | |
210 break | |
211 | |
212 tempname = changegroup.writebundle(cg, None, type) | |
213 fp = url.httpsendfile(tempname, "rb") | |
214 try: | |
215 try: | |
216 resp = self.do_read( | |
217 'unbundle', data=fp, | |
218 headers={'Content-Type': 'application/octet-stream'}, | |
219 heads=' '.join(map(hex, heads))) | |
220 resp_code, output = resp.split('\n', 1) | |
221 try: | |
222 ret = int(resp_code) | |
223 except ValueError, err: | |
224 raise error.ResponseError( | |
225 _('push failed (unexpected response):'), resp) | |
226 self.ui.write(output) | |
227 return ret | |
228 except socket.error, err: | |
229 if err[0] in (errno.ECONNRESET, errno.EPIPE): | |
230 raise util.Abort(_('push failed: %s') % err[1]) | |
231 raise util.Abort(err[1]) | |
232 finally: | |
233 fp.close() | |
234 os.unlink(tempname) | |
235 | |
236 def stream_out(self): | |
237 return self.do_cmd('stream_out') | |
238 | |
239 class httpsrepository(httprepository): | |
240 def __init__(self, ui, path): | |
241 if not url.has_https: | |
242 raise util.Abort(_('Python support for SSL and HTTPS ' | |
243 'is not installed')) | |
244 httprepository.__init__(self, ui, path) | |
245 | |
246 def instance(ui, path, create): | |
247 if create: | |
248 raise util.Abort(_('cannot create new http repository')) | |
249 try: | |
250 if path.startswith('https:'): | |
251 inst = httpsrepository(ui, path) | |
252 else: | |
253 inst = httprepository(ui, path) | |
254 inst.between([(nullid, nullid)]) | |
255 return inst | |
256 except error.RepoError: | |
257 ui.note('(falling back to static-http)\n') | |
258 return statichttprepo.instance(ui, "static-" + path, create) |