Mercurial > traipse_dev
comparison upmana/mercurial/httprepo.py @ 121:496dbf12a6cb alpha
Traipse Alpha 'OpenRPG' {091030-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 (Cleaning up for Beta):
Adds Bookmarks (Alpha) with cool Smiley Star and Plus Symbol images!
Changes made to the map for increased portability. SnowDog has changes planned in
Core, though.
Added an initial push to the BCG. Not much to see, just shows off how it is
re-writing Main code.
Fix to remote admin commands
Minor fix to texted based server, works in /System/ folder
Some Core changes to gametree to correctly disply Pretty Print, thanks David!
Fix to Splitter Nodes not being created.
Added images to Plugin Control panel for Autostart feature
Fix to massive amounts of images loading; from Core
fix to gsclient so with_statement imports
Added 'boot' command to remote admin
Prep work in Pass tool for remote admin rankings and different passwords, ei,
Server, Admin, Moderator, etc.
Remote Admin Commands more organized, more prep work.
Added Confirmation window for sent nodes.
Minor changes to allow for portability to an OpenSUSE linux OS (hopefully without
breaking)
{091028}
Made changes to gametree to start working with Element Tree, mostly from Core
Minor changes to Map to start working with Element Tree, from Core
Preliminary changes to map efficiency, from FlexiRPG
Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG
Changes to main.py to start working with Element Tree
{091029}
Changes made to server to start working with Element Tree.
Changes made to Meta Server Lib. Prepping test work for a multi meta network
page.
Minor bug fixed with mini to gametree
Zoom Mouse plugin added.
{091030}
Getting ready for Beta. Server needs debugging so Alpha remains bugged.
Plugin UI code cleaned. Auto start works with a graphic, pop-up asks to enable or
disable plugin.
Update Manager now has a partially working Status Bar. Status Bar captures
terminal text, so Merc out put is visible. Manifest.xml file, will be renamed, is
now much cleaner.
Debug Console has a clear button and a Report Bug button. Prep work for a Term2Win
class in Debug Console.
Known: Current Alpha fails in Windows.
author | sirebral |
---|---|
date | Fri, 30 Oct 2009 22:21:40 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
120:d86e762a994f | 121:496dbf12a6cb |
---|---|
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) |