##// END OF EJS Templates
statichttprepo: make the opener a subclass of abstractopener
Dan Villiom Podlaski Christiansen -
r14091:0aa60e4e default
parent child Browse files
Show More
@@ -1,147 +1,147 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 i18n import _
10 from i18n import _
11 import changelog, byterange, url, error
11 import changelog, byterange, url, error
12 import localrepo, manifest, util, store
12 import localrepo, manifest, util, scmutil, store
13 import urllib, urllib2, errno
13 import urllib, urllib2, errno
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 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
29 req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
30
30
31 try:
31 try:
32 f = self.opener.open(req)
32 f = self.opener.open(req)
33 data = f.read()
33 data = f.read()
34 if hasattr(f, 'getcode'):
34 if hasattr(f, 'getcode'):
35 # python 2.6+
35 # python 2.6+
36 code = f.getcode()
36 code = f.getcode()
37 elif hasattr(f, 'code'):
37 elif hasattr(f, 'code'):
38 # undocumented attribute, seems to be set in 2.4 and 2.5
38 # undocumented attribute, seems to be set in 2.4 and 2.5
39 code = f.code
39 code = f.code
40 else:
40 else:
41 # Don't know how to check, hope for the best.
41 # Don't know how to check, hope for the best.
42 code = 206
42 code = 206
43 except urllib2.HTTPError, inst:
43 except urllib2.HTTPError, inst:
44 num = inst.code == 404 and errno.ENOENT or None
44 num = inst.code == 404 and errno.ENOENT or None
45 raise IOError(num, inst)
45 raise IOError(num, inst)
46 except urllib2.URLError, inst:
46 except urllib2.URLError, inst:
47 raise IOError(None, inst.reason[1])
47 raise IOError(None, inst.reason[1])
48
48
49 if code == 200:
49 if code == 200:
50 # HTTPRangeHandler does nothing if remote does not support
50 # HTTPRangeHandler does nothing if remote does not support
51 # Range headers and returns the full entity. Let's slice it.
51 # Range headers and returns the full entity. Let's slice it.
52 if bytes:
52 if bytes:
53 data = data[self.pos:self.pos + bytes]
53 data = data[self.pos:self.pos + bytes]
54 else:
54 else:
55 data = data[self.pos:]
55 data = data[self.pos:]
56 elif bytes:
56 elif bytes:
57 data = data[:bytes]
57 data = data[:bytes]
58 self.pos += len(data)
58 self.pos += len(data)
59 return data
59 return data
60 def __iter__(self):
60 def __iter__(self):
61 return iter(self.read().splitlines(1))
61 return iter(self.read().splitlines(1))
62 def close(self):
62 def close(self):
63 pass
63 pass
64
64
65 def build_opener(ui, authinfo):
65 def build_opener(ui, authinfo):
66 # urllib cannot handle URLs with embedded user or passwd
66 # urllib cannot handle URLs with embedded user or passwd
67 urlopener = url.opener(ui, authinfo)
67 urlopener = url.opener(ui, authinfo)
68 urlopener.add_handler(byterange.HTTPRangeHandler())
68 urlopener.add_handler(byterange.HTTPRangeHandler())
69
69
70 def opener(base):
70 class statichttpopener(scmutil.abstractopener):
71 """return a function that opens files over http"""
71 def __init__(self, base):
72 p = base
72 self.base = base
73 def o(path, mode="r", atomictemp=None):
73
74 def __call__(self, path, mode="r", atomictemp=None):
74 if mode not in ('r', 'rb'):
75 if mode not in ('r', 'rb'):
75 raise IOError('Permission denied')
76 raise IOError('Permission denied')
76 f = "/".join((p, urllib.quote(path)))
77 f = "/".join((self.base, urllib.quote(path)))
77 return httprangereader(f, urlopener)
78 return httprangereader(f, urlopener)
78 return o
79
79
80 return opener
80 return statichttpopener
81
81
82 class statichttprepository(localrepo.localrepository):
82 class statichttprepository(localrepo.localrepository):
83 def __init__(self, ui, path):
83 def __init__(self, ui, path):
84 self._url = path
84 self._url = path
85 self.ui = ui
85 self.ui = ui
86
86
87 self.root = path
87 self.root = path
88 u = util.url(path.rstrip('/') + "/.hg")
88 u = util.url(path.rstrip('/') + "/.hg")
89 self.path, authinfo = u.authinfo()
89 self.path, authinfo = u.authinfo()
90
90
91 opener = build_opener(ui, authinfo)
91 opener = build_opener(ui, authinfo)
92 self.opener = opener(self.path)
92 self.opener = opener(self.path)
93
93
94 # find requirements
94 # find requirements
95 try:
95 try:
96 requirements = self.opener("requires").read().splitlines()
96 requirements = self.opener("requires").read().splitlines()
97 except IOError, inst:
97 except IOError, inst:
98 if inst.errno != errno.ENOENT:
98 if inst.errno != errno.ENOENT:
99 raise
99 raise
100 # check if it is a non-empty old-style repository
100 # check if it is a non-empty old-style repository
101 try:
101 try:
102 fp = self.opener("00changelog.i")
102 fp = self.opener("00changelog.i")
103 fp.read(1)
103 fp.read(1)
104 fp.close()
104 fp.close()
105 except IOError, inst:
105 except IOError, inst:
106 if inst.errno != errno.ENOENT:
106 if inst.errno != errno.ENOENT:
107 raise
107 raise
108 # we do not care about empty old-style repositories here
108 # we do not care about empty old-style repositories here
109 msg = _("'%s' does not appear to be an hg repository") % path
109 msg = _("'%s' does not appear to be an hg repository") % path
110 raise error.RepoError(msg)
110 raise error.RepoError(msg)
111 requirements = []
111 requirements = []
112
112
113 # check them
113 # check them
114 for r in requirements:
114 for r in requirements:
115 if r not in self.supported:
115 if r not in self.supported:
116 raise error.RequirementError(
116 raise error.RequirementError(
117 _("requirement '%s' not supported") % r)
117 _("requirement '%s' not supported") % r)
118
118
119 # setup store
119 # setup store
120 self.store = store.store(requirements, self.path, opener)
120 self.store = store.store(requirements, self.path, opener)
121 self.spath = self.store.path
121 self.spath = self.store.path
122 self.sopener = self.store.opener
122 self.sopener = self.store.opener
123 self.sjoin = self.store.join
123 self.sjoin = self.store.join
124
124
125 self.manifest = manifest.manifest(self.sopener)
125 self.manifest = manifest.manifest(self.sopener)
126 self.changelog = changelog.changelog(self.sopener)
126 self.changelog = changelog.changelog(self.sopener)
127 self._tags = None
127 self._tags = None
128 self.nodetagscache = None
128 self.nodetagscache = None
129 self._branchcache = None
129 self._branchcache = None
130 self._branchcachetip = None
130 self._branchcachetip = None
131 self.encodepats = None
131 self.encodepats = None
132 self.decodepats = None
132 self.decodepats = None
133 self.capabilities = self.capabilities.difference(["pushkey"])
133 self.capabilities = self.capabilities.difference(["pushkey"])
134
134
135 def url(self):
135 def url(self):
136 return self._url
136 return self._url
137
137
138 def local(self):
138 def local(self):
139 return False
139 return False
140
140
141 def lock(self, wait=True):
141 def lock(self, wait=True):
142 raise util.Abort(_('cannot lock static-http repository'))
142 raise util.Abort(_('cannot lock static-http repository'))
143
143
144 def instance(ui, path, create):
144 def instance(ui, path, create):
145 if create:
145 if create:
146 raise util.Abort(_('cannot create new static-http repository'))
146 raise util.Abort(_('cannot create new static-http repository'))
147 return statichttprepository(ui, path[7:])
147 return statichttprepository(ui, path[7:])
General Comments 0
You need to be logged in to leave comments. Login now