Kiln » Kiln Extensions
Clone URL:  
httpstore.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
'''HTTP-based store.''' import inspect, urlparse, urllib2 from mercurial import util, hg, url as url_ from mercurial.i18n import _ try: from mercurial import httpconnection except ImportError: pass import bfutil, basestore class httpstore(basestore.basestore): """A store accessed via HTTP""" def __init__(self, ui, repo, url): store_type = None try: remoterepo = hg.peer(repo, dict([]), url) store_type = remoterepo.capable('bfilestore') except: pass if store_type == 'serve': self.proto = hgservestoreproto(remoterepo, url) elif store_type == 'kiln': self.proto = kilnstoreproto(ui, url) else: ui.note(_('bfilestore capability not found; assuming %s is a Kiln repo') % url) self.proto = kilnstoreproto(ui, url) self.url = self.proto.url self.rawurl, authinfo = urlparse.urlsplit(self.url)[1:3] super(httpstore, self).__init__(ui, repo, url) def put(self, source, hash): self.sendfile(source, hash) if not self._verify(hash): raise util.Abort(_('could not put %s to remote store') % source) self.ui.debug('put %s to remote store\n' % source) def exists(self, hash): return self._verify(hash) def sendfile(self, filename, hash): if self._verify(hash): return self.ui.debug('httpstore.sendfile(%s, %s)\n' % (filename, hash)) Ffd = None try: try: # Mercurial >= 1.9 fd = httpconnection.httpsendfile(self.ui, filename, 'rb') except ImportError: if 'ui' in inspect.getargspec(url_.httpsendfile.__init__)[0]: # Mercurial == 1.8 fd = url_.httpsendfile(self.ui, filename, 'rb') else: # Mercurial <= 1.7 fd = url_.httpsendfile(filename, 'rb') try: url = self.proto.put(hash, fd) except urllib2.HTTPError, e: raise util.Abort(_('unable to POST: %s\n') % e.msg) except Exception, e: raise util.Abort(_('%s') % e) finally: if fd: fd.close() def _getfile(self, tmpfile, filename, hash): stat = self.proto.stat(hash) if stat: raise util.Abort(_('bfile %s is %s') % (hash, 'invalid' if stat == 1 else 'missing')) try: infile = self.proto.get(hash) except urllib2.HTTPError, err: detail = _("HTTP error: %s %s") % (err.code, err.msg) raise basestore.StoreError(filename, hash, self.url, detail) except urllib2.URLError, err: # This usually indicates a connection problem, so don't # keep trying with the other files... they will probably # all fail too. reason = err[0][1] # assumes err[0] is a socket.error raise util.Abort('%s: %s' % (self.url, reason)) return bfutil.copyandhash(bfutil.blockstream(infile), tmpfile) def _verify(self, hash): return not self.proto.stat(hash) def _verifyfile(self, cctx, cset, contents, standin, verified): filename = bfutil.splitstandin(standin) if not filename: return False fctx = cctx[standin] key = (filename, fctx.filenode()) if key in verified: return False expect_hash = fctx.data()[0:40] verified.add(key) stat = self.proto.stat(hash) if not stat: return False elif stat == 1: self.ui.warn( _('changeset %s: %s: contents differ\n (%s)\n') % (cset, filename, store_path)) return True # failed elif stat == 2: self.ui.warn( _('changeset %s: %s missing\n (%s)\n') % (cset, filename, store_path)) return True # failed else: raise util.Abort(_('check failed, unexpected response' 'statbfile: %d') % stat) class kilnstoreproto(object): def __init__(self, ui, url): self.url = bfutil.urljoin(url, "bfile") try: # Mercurial >= 1.9 baseurl, authinfo = util.url(self.url).authinfo() except AttributeError: # Mercurial <= 1.8 baseurl, authinfo = url_.getauthinfo(self.url) self.opener = url_.opener(ui, authinfo) def put(self, hash, fd): req = urllib2.Request(bfutil.urljoin(self.url, hash), fd) return self.opener.open(req) def get(self, hash): req = urllib2.Request(bfutil.urljoin(self.url, hash)) req.add_header('SHA1-Request', hash) return self.opener.open(req) # '0' for OK, '1' for invalid checksum, '2' for missing def stat(self, hash): try: return 0 if hash == bfutil.hexsha1(self.get(hash)) else 1 except urllib2.HTTPError, e: if e.code == 404: return 2 else: raise class hgservestoreproto(object): def __init__(self, repo, url): self.repo = repo self.url = url def put(self, hash, fd): return self.repo.putbfile(hash, fd) def get(self, hash): return self.repo.getbfile(hash) def stat(self, hash): return self.repo.statbfile(hash)