##// END OF EJS Templates
statichttprepo: implement __enter__ and __exit__ on httprangeheader...
Gregory Szorc -
r27705:2380889f default
parent child Browse files
Show More
@@ -1,179 +1,186 b''
1 1 # statichttprepo.py - simple http repository class for mercurial
2 2 #
3 3 # This provides read-only repo access to repositories exported via static http
4 4 #
5 5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 from __future__ import absolute_import
11 11
12 12 import errno
13 13 import os
14 14 import urllib
15 15 import urllib2
16 16
17 17 from .i18n import _
18 18 from . import (
19 19 byterange,
20 20 changelog,
21 21 error,
22 22 localrepo,
23 23 manifest,
24 24 namespaces,
25 25 scmutil,
26 26 store,
27 27 url,
28 28 util,
29 29 )
30 30
31 31 class httprangereader(object):
32 32 def __init__(self, url, opener):
33 33 # we assume opener has HTTPRangeHandler
34 34 self.url = url
35 35 self.pos = 0
36 36 self.opener = opener
37 37 self.name = url
38
39 def __enter__(self):
40 return self
41
42 def __exit__(self, exc_type, exc_value, traceback):
43 self.close()
44
38 45 def seek(self, pos):
39 46 self.pos = pos
40 47 def read(self, bytes=None):
41 48 req = urllib2.Request(self.url)
42 49 end = ''
43 50 if bytes:
44 51 end = self.pos + bytes - 1
45 52 if self.pos or end:
46 53 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
47 54
48 55 try:
49 56 f = self.opener.open(req)
50 57 data = f.read()
51 58 code = f.code
52 59 except urllib2.HTTPError as inst:
53 60 num = inst.code == 404 and errno.ENOENT or None
54 61 raise IOError(num, inst)
55 62 except urllib2.URLError as inst:
56 63 raise IOError(None, inst.reason[1])
57 64
58 65 if code == 200:
59 66 # HTTPRangeHandler does nothing if remote does not support
60 67 # Range headers and returns the full entity. Let's slice it.
61 68 if bytes:
62 69 data = data[self.pos:self.pos + bytes]
63 70 else:
64 71 data = data[self.pos:]
65 72 elif bytes:
66 73 data = data[:bytes]
67 74 self.pos += len(data)
68 75 return data
69 76 def readlines(self):
70 77 return self.read().splitlines(True)
71 78 def __iter__(self):
72 79 return iter(self.readlines())
73 80 def close(self):
74 81 pass
75 82
76 83 def build_opener(ui, authinfo):
77 84 # urllib cannot handle URLs with embedded user or passwd
78 85 urlopener = url.opener(ui, authinfo)
79 86 urlopener.add_handler(byterange.HTTPRangeHandler())
80 87
81 88 class statichttpvfs(scmutil.abstractvfs):
82 89 def __init__(self, base):
83 90 self.base = base
84 91
85 92 def __call__(self, path, mode='r', *args, **kw):
86 93 if mode not in ('r', 'rb'):
87 94 raise IOError('Permission denied')
88 95 f = "/".join((self.base, urllib.quote(path)))
89 96 return httprangereader(f, urlopener)
90 97
91 98 def join(self, path):
92 99 if path:
93 100 return os.path.join(self.base, path)
94 101 else:
95 102 return self.base
96 103
97 104 return statichttpvfs
98 105
99 106 class statichttppeer(localrepo.localpeer):
100 107 def local(self):
101 108 return None
102 109 def canpush(self):
103 110 return False
104 111
105 112 class statichttprepository(localrepo.localrepository):
106 113 supported = localrepo.localrepository._basesupported
107 114
108 115 def __init__(self, ui, path):
109 116 self._url = path
110 117 self.ui = ui
111 118
112 119 self.root = path
113 120 u = util.url(path.rstrip('/') + "/.hg")
114 121 self.path, authinfo = u.authinfo()
115 122
116 123 opener = build_opener(ui, authinfo)
117 124 self.opener = opener(self.path)
118 125 self.vfs = self.opener
119 126 self._phasedefaults = []
120 127
121 128 self.names = namespaces.namespaces()
122 129
123 130 try:
124 131 requirements = scmutil.readrequires(self.vfs, self.supported)
125 132 except IOError as inst:
126 133 if inst.errno != errno.ENOENT:
127 134 raise
128 135 requirements = set()
129 136
130 137 # check if it is a non-empty old-style repository
131 138 try:
132 139 fp = self.vfs("00changelog.i")
133 140 fp.read(1)
134 141 fp.close()
135 142 except IOError as inst:
136 143 if inst.errno != errno.ENOENT:
137 144 raise
138 145 # we do not care about empty old-style repositories here
139 146 msg = _("'%s' does not appear to be an hg repository") % path
140 147 raise error.RepoError(msg)
141 148
142 149 # setup store
143 150 self.store = store.store(requirements, self.path, opener)
144 151 self.spath = self.store.path
145 152 self.svfs = self.store.opener
146 153 self.sjoin = self.store.join
147 154 self._filecache = {}
148 155 self.requirements = requirements
149 156
150 157 self.manifest = manifest.manifest(self.svfs)
151 158 self.changelog = changelog.changelog(self.svfs)
152 159 self._tags = None
153 160 self.nodetagscache = None
154 161 self._branchcaches = {}
155 162 self._revbranchcache = None
156 163 self.encodepats = None
157 164 self.decodepats = None
158 165 self._transref = None
159 166
160 167 def _restrictcapabilities(self, caps):
161 168 caps = super(statichttprepository, self)._restrictcapabilities(caps)
162 169 return caps.difference(["pushkey"])
163 170
164 171 def url(self):
165 172 return self._url
166 173
167 174 def local(self):
168 175 return False
169 176
170 177 def peer(self):
171 178 return statichttppeer(self)
172 179
173 180 def lock(self, wait=True):
174 181 raise error.Abort(_('cannot lock static-http repository'))
175 182
176 183 def instance(ui, path, create):
177 184 if create:
178 185 raise error.Abort(_('cannot create new static-http repository'))
179 186 return statichttprepository(ui, path[7:])
General Comments 0
You need to be logged in to leave comments. Login now