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