163
164
def has(self, relpath):
164
165
raise NotImplementedError("has() is abstract on %r" % self)
166
def stat(self, relpath):
167
"""Return the stat information for a file.
169
raise TransportNotPossible('http does not support stat()')
171
def lock_read(self, relpath):
172
"""Lock the given file for shared (read) access.
173
:return: A lock object, which should be passed to Transport.unlock()
175
# The old RemoteBranch ignore lock for reading, so we will
176
# continue that tradition and return a bogus lock object.
177
class BogusLock(object):
178
def __init__(self, path):
182
return BogusLock(relpath)
184
def lock_write(self, relpath):
185
"""Lock the given file for exclusive (write) access.
186
WARNING: many transports do not support this, so trying avoid using it
188
:return: A lock object, which should be passed to Transport.unlock()
190
raise TransportNotPossible('http does not support lock_write()')
192
def clone(self, offset=None):
193
"""Return a new HttpTransportBase with root at self.base + offset
194
For now HttpTransportBase does not actually connect, so just return
195
a new HttpTransportBase object.
198
return self.__class__(self.base)
200
return self.__class__(self.abspath(offset))
203
"""Returns false - http has no reliable way to list directories."""
204
# well, we could try DAV...
167
def get(self, relpath):
168
"""Get the file at the given relative path.
170
:param relpath: The relative path to the file
172
return self._get(relpath, [])
174
def _get(self, relpath, ranges):
175
"""GET a file over http
177
:param relpath: URL relative to base of this Transport
178
:param ranges: None to fetch the whole resource; or a string giving the bytes
181
raise NotImplementedError(self._get)
183
def readv(self, relpath, offsets):
184
"""Get parts of the file at the given relative path.
186
:param offsets: A list of (offset, size) tuples.
187
:return: A list or generator of (offset, data) tuples
189
# this is not quite regular enough to have a single driver routine and
190
# helper method in Transport.
191
def do_combined_read(combined_offsets):
192
# read one coalesced block
194
for offset, size in combined_offsets:
196
mutter('readv coalesced %d reads.', len(combined_offsets))
197
offset = combined_offsets[0][0]
198
ranges = 'bytes=%d-%d' % (offset, offset + total_size - 1)
199
response = self._get(relpath, ranges=ranges)
200
if response.code == 206:
201
for off, size in combined_offsets:
202
yield off, response.read(size)
203
elif response.code == 200:
204
data = response.read(offset + total_size)[offset:offset + total_size]
206
for offset, size in combined_offsets:
207
yield offset, data[pos:pos + size]
213
pending_offsets = deque(offsets)
214
combined_offsets = []
215
while len(pending_offsets):
216
offset, size = pending_offsets.popleft()
217
if not combined_offsets:
218
combined_offsets = [[offset, size]]
220
if (len (combined_offsets) < 500 and
221
combined_offsets[-1][0] + combined_offsets[-1][1] == offset):
223
combined_offsets.append([offset, size])
225
# incompatible, or over the threshold issue a read and yield
226
pending_offsets.appendleft((offset, size))
227
for result in do_combined_read(combined_offsets):
229
combined_offsets = []
230
# whatever is left is a single coalesced request
231
if len(combined_offsets):
232
for result in do_combined_read(combined_offsets):
207
235
def put(self, relpath, f, mode=None):
208
236
"""Copy the file-like or string object into the location.
238
266
TODO: if other is LocalTransport, is it possible to
239
267
do better than put(get())?
241
# At this point HttpTransportBase might be able to check and see if
269
# At this point HttpTransport might be able to check and see if
242
270
# the remote location is the same, and rather than download, and
243
271
# then upload, it could just issue a remote copy_this command.
244
272
if isinstance(other, HttpTransportBase):
245
273
raise TransportNotPossible('http cannot be the target of copy_to()')
247
return super(HttpTransportBase, self).copy_to(relpaths, other, mode=mode, pb=pb)
275
return super(HttpTransportBase, self).\
276
copy_to(relpaths, other, mode=mode, pb=pb)
249
278
def move(self, rel_from, rel_to):
250
279
"""Move the item at rel_from to the location at rel_to"""