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