comparison upmana/mercurial/httprepo.py @ 28:ff154cf3350c ornery-orc

Traipse 'OpenRPG' {100203-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 (Stable) New Features: New Bookmarks Feature New 'boot' command to remote admin New confirmation window for sent nodes Miniatures Layer pop up box allows users to turn off Mini labels, from FlexiRPG New Zoom Mouse plugin added New Images added to Plugin UI Switching to Element Tree New Map efficiency, from FlexiRPG New Status Bar to Update Manager New TrueDebug Class in orpg_log (See documentation for usage) New Portable Mercurial New Tip of the Day, from Core and community New Reference Syntax added for custom PC sheets New Child Reference for gametree New Parent Reference for gametree New Gametree Recursion method, mapping, context sensitivity, and effeciency.. New Features node with bonus nodes and Node Referencing help added New Dieroller structure from Core New DieRoller portability for odd Dice New 7th Sea die roller; ie [7k3] = [7d10.takeHighest(3).open(10)] New 'Mythos' System die roller added New vs. die roller method for WoD; ie [3v3] = [3d10.vs(3)]. Included for Mythos roller also New Warhammer FRPG Die Roller (Special thanks to Puu-san for the support) New EZ_Tree Reference system. Push a button, Traipse the tree, get a reference (Beta!) New Grids act more like Spreadsheets in Use mode, with Auto Calc Fixes: Fix to allow for portability to an OpenSUSE linux OS Fix to mplay_client for Fedora and OpenSUSE Fix to Text based Server Fix to Remote Admin Commands Fix to Pretty Print, from Core Fix to Splitter Nodes not being created Fix to massive amounts of images loading, from Core Fix to Map from gametree not showing to all clients Fix to gametree about menus Fix to Password Manager check on startup Fix to PC Sheets from tool nodes. They now use the tabber_panel Fix to Whiteboard ID to prevent random line or text deleting. Fixes to Server, Remote Server, and Server GUI Fix to Update Manager; cleaner clode for saved repositories Fixes made to Settings Panel and now reactive settings when Ok is pressed Fixes to Alternity roller's attack roll. Uses a simple Tuple instead of a Splice Fix to Use panel of Forms and Tabbers. Now longer enters design mode Fix made Image Fetching. New fetching image and new failed image Fix to whiteboard ID's to prevent non updated clients from ruining the fix. default_manifest.xml renamed to default_upmana.xml
author sirebral
date Wed, 03 Feb 2010 22:16:49 -0600
parents
children
comparison
equal deleted inserted replaced
27:51428d30c59e 28:ff154cf3350c
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)