##// END OF EJS Templates
statichttprepo: remove wrong getattr ladder...
Augie Fackler -
r25196:7a1af58a default
parent child Browse files
Show More
@@ -1,168 +1,164
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 i18n import _
10 from i18n import _
11 import changelog, byterange, url, error, namespaces
11 import changelog, byterange, url, error, namespaces
12 import localrepo, manifest, util, scmutil, store
12 import localrepo, manifest, util, scmutil, store
13 import urllib, urllib2, errno, os
13 import urllib, urllib2, errno, os
14
14
15 class httprangereader(object):
15 class httprangereader(object):
16 def __init__(self, url, opener):
16 def __init__(self, url, opener):
17 # we assume opener has HTTPRangeHandler
17 # we assume opener has HTTPRangeHandler
18 self.url = url
18 self.url = url
19 self.pos = 0
19 self.pos = 0
20 self.opener = opener
20 self.opener = opener
21 self.name = url
21 self.name = url
22 def seek(self, pos):
22 def seek(self, pos):
23 self.pos = pos
23 self.pos = pos
24 def read(self, bytes=None):
24 def read(self, bytes=None):
25 req = urllib2.Request(self.url)
25 req = urllib2.Request(self.url)
26 end = ''
26 end = ''
27 if bytes:
27 if bytes:
28 end = self.pos + bytes - 1
28 end = self.pos + bytes - 1
29 if self.pos or end:
29 if self.pos or end:
30 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
30 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
31
31
32 try:
32 try:
33 f = self.opener.open(req)
33 f = self.opener.open(req)
34 data = f.read()
34 data = f.read()
35 # Python 2.6+ defines a getcode() function, and 2.4 and
35 code = f.code
36 # 2.5 appear to always have an undocumented code attribute
37 # set. If we can't read either of those, fall back to 206
38 # and hope for the best.
39 code = getattr(f, 'getcode', lambda : getattr(f, 'code', 206))()
40 except urllib2.HTTPError, inst:
36 except urllib2.HTTPError, inst:
41 num = inst.code == 404 and errno.ENOENT or None
37 num = inst.code == 404 and errno.ENOENT or None
42 raise IOError(num, inst)
38 raise IOError(num, inst)
43 except urllib2.URLError, inst:
39 except urllib2.URLError, inst:
44 raise IOError(None, inst.reason[1])
40 raise IOError(None, inst.reason[1])
45
41
46 if code == 200:
42 if code == 200:
47 # HTTPRangeHandler does nothing if remote does not support
43 # HTTPRangeHandler does nothing if remote does not support
48 # Range headers and returns the full entity. Let's slice it.
44 # Range headers and returns the full entity. Let's slice it.
49 if bytes:
45 if bytes:
50 data = data[self.pos:self.pos + bytes]
46 data = data[self.pos:self.pos + bytes]
51 else:
47 else:
52 data = data[self.pos:]
48 data = data[self.pos:]
53 elif bytes:
49 elif bytes:
54 data = data[:bytes]
50 data = data[:bytes]
55 self.pos += len(data)
51 self.pos += len(data)
56 return data
52 return data
57 def readlines(self):
53 def readlines(self):
58 return self.read().splitlines(True)
54 return self.read().splitlines(True)
59 def __iter__(self):
55 def __iter__(self):
60 return iter(self.readlines())
56 return iter(self.readlines())
61 def close(self):
57 def close(self):
62 pass
58 pass
63
59
64 def build_opener(ui, authinfo):
60 def build_opener(ui, authinfo):
65 # urllib cannot handle URLs with embedded user or passwd
61 # urllib cannot handle URLs with embedded user or passwd
66 urlopener = url.opener(ui, authinfo)
62 urlopener = url.opener(ui, authinfo)
67 urlopener.add_handler(byterange.HTTPRangeHandler())
63 urlopener.add_handler(byterange.HTTPRangeHandler())
68
64
69 class statichttpvfs(scmutil.abstractvfs):
65 class statichttpvfs(scmutil.abstractvfs):
70 def __init__(self, base):
66 def __init__(self, base):
71 self.base = base
67 self.base = base
72
68
73 def __call__(self, path, mode='r', *args, **kw):
69 def __call__(self, path, mode='r', *args, **kw):
74 if mode not in ('r', 'rb'):
70 if mode not in ('r', 'rb'):
75 raise IOError('Permission denied')
71 raise IOError('Permission denied')
76 f = "/".join((self.base, urllib.quote(path)))
72 f = "/".join((self.base, urllib.quote(path)))
77 return httprangereader(f, urlopener)
73 return httprangereader(f, urlopener)
78
74
79 def join(self, path):
75 def join(self, path):
80 if path:
76 if path:
81 return os.path.join(self.base, path)
77 return os.path.join(self.base, path)
82 else:
78 else:
83 return self.base
79 return self.base
84
80
85 return statichttpvfs
81 return statichttpvfs
86
82
87 class statichttppeer(localrepo.localpeer):
83 class statichttppeer(localrepo.localpeer):
88 def local(self):
84 def local(self):
89 return None
85 return None
90 def canpush(self):
86 def canpush(self):
91 return False
87 return False
92
88
93 class statichttprepository(localrepo.localrepository):
89 class statichttprepository(localrepo.localrepository):
94 supported = localrepo.localrepository._basesupported
90 supported = localrepo.localrepository._basesupported
95
91
96 def __init__(self, ui, path):
92 def __init__(self, ui, path):
97 self._url = path
93 self._url = path
98 self.ui = ui
94 self.ui = ui
99
95
100 self.root = path
96 self.root = path
101 u = util.url(path.rstrip('/') + "/.hg")
97 u = util.url(path.rstrip('/') + "/.hg")
102 self.path, authinfo = u.authinfo()
98 self.path, authinfo = u.authinfo()
103
99
104 opener = build_opener(ui, authinfo)
100 opener = build_opener(ui, authinfo)
105 self.opener = opener(self.path)
101 self.opener = opener(self.path)
106 self.vfs = self.opener
102 self.vfs = self.opener
107 self._phasedefaults = []
103 self._phasedefaults = []
108
104
109 self.names = namespaces.namespaces()
105 self.names = namespaces.namespaces()
110
106
111 try:
107 try:
112 requirements = scmutil.readrequires(self.vfs, self.supported)
108 requirements = scmutil.readrequires(self.vfs, self.supported)
113 except IOError, inst:
109 except IOError, inst:
114 if inst.errno != errno.ENOENT:
110 if inst.errno != errno.ENOENT:
115 raise
111 raise
116 requirements = set()
112 requirements = set()
117
113
118 # check if it is a non-empty old-style repository
114 # check if it is a non-empty old-style repository
119 try:
115 try:
120 fp = self.vfs("00changelog.i")
116 fp = self.vfs("00changelog.i")
121 fp.read(1)
117 fp.read(1)
122 fp.close()
118 fp.close()
123 except IOError, inst:
119 except IOError, inst:
124 if inst.errno != errno.ENOENT:
120 if inst.errno != errno.ENOENT:
125 raise
121 raise
126 # we do not care about empty old-style repositories here
122 # we do not care about empty old-style repositories here
127 msg = _("'%s' does not appear to be an hg repository") % path
123 msg = _("'%s' does not appear to be an hg repository") % path
128 raise error.RepoError(msg)
124 raise error.RepoError(msg)
129
125
130 # setup store
126 # setup store
131 self.store = store.store(requirements, self.path, opener)
127 self.store = store.store(requirements, self.path, opener)
132 self.spath = self.store.path
128 self.spath = self.store.path
133 self.svfs = self.store.opener
129 self.svfs = self.store.opener
134 self.sopener = self.svfs
130 self.sopener = self.svfs
135 self.sjoin = self.store.join
131 self.sjoin = self.store.join
136 self._filecache = {}
132 self._filecache = {}
137 self.requirements = requirements
133 self.requirements = requirements
138
134
139 self.manifest = manifest.manifest(self.svfs)
135 self.manifest = manifest.manifest(self.svfs)
140 self.changelog = changelog.changelog(self.svfs)
136 self.changelog = changelog.changelog(self.svfs)
141 self._tags = None
137 self._tags = None
142 self.nodetagscache = None
138 self.nodetagscache = None
143 self._branchcaches = {}
139 self._branchcaches = {}
144 self._revbranchcache = None
140 self._revbranchcache = None
145 self.encodepats = None
141 self.encodepats = None
146 self.decodepats = None
142 self.decodepats = None
147 self._transref = None
143 self._transref = None
148
144
149 def _restrictcapabilities(self, caps):
145 def _restrictcapabilities(self, caps):
150 caps = super(statichttprepository, self)._restrictcapabilities(caps)
146 caps = super(statichttprepository, self)._restrictcapabilities(caps)
151 return caps.difference(["pushkey"])
147 return caps.difference(["pushkey"])
152
148
153 def url(self):
149 def url(self):
154 return self._url
150 return self._url
155
151
156 def local(self):
152 def local(self):
157 return False
153 return False
158
154
159 def peer(self):
155 def peer(self):
160 return statichttppeer(self)
156 return statichttppeer(self)
161
157
162 def lock(self, wait=True):
158 def lock(self, wait=True):
163 raise util.Abort(_('cannot lock static-http repository'))
159 raise util.Abort(_('cannot lock static-http repository'))
164
160
165 def instance(ui, path, create):
161 def instance(ui, path, create):
166 if create:
162 if create:
167 raise util.Abort(_('cannot create new static-http repository'))
163 raise util.Abort(_('cannot create new static-http repository'))
168 return statichttprepository(ui, path[7:])
164 return statichttprepository(ui, path[7:])
General Comments 0
You need to be logged in to leave comments. Login now