66
66
from bzrlib import registry
69
# a dictionary of open file streams. Keys are absolute paths, values are
69
74
def _get_protocol_handlers():
70
75
"""Return a dictionary of {urlprefix: [factory]}"""
71
76
return transport_list_registry
260
class FileStream(object):
261
"""Base class for FileStreams."""
263
def __init__(self, transport, relpath):
264
"""Create a FileStream for relpath on transport."""
265
self.transport = transport
266
self.relpath = relpath
269
"""A hook point for subclasses that need to take action on close."""
273
del _file_streams[self.transport.abspath(self.relpath)]
276
class FileFileStream(FileStream):
277
"""A file stream object returned by open_write_stream.
279
This version uses a file like object to perform writes.
282
def __init__(self, transport, relpath, file_handle):
283
FileStream.__init__(self, transport, relpath)
284
self.file_handle = file_handle
287
self.file_handle.close()
289
def write(self, bytes):
290
self.file_handle.write(bytes)
293
class AppendBasedFileStream(FileStream):
294
"""A file stream object returned by open_write_stream.
296
This version uses append on a transport to perform writes.
299
def write(self, bytes):
300
self.transport.append_bytes(self.relpath, bytes)
255
303
class Transport(object):
256
304
"""This class encapsulates methods for retrieving or putting a file
257
305
from/to a storage location.
352
400
raise NotImplementedError(self.external_url)
354
def should_cache(self):
355
"""Return True if the data pulled across should be cached locally.
359
402
def _pump(self, from_file, to_file):
360
403
"""Most children will need to copy from one file-like
361
404
object or string to another one.
460
503
path = '/' + path
506
def recommended_page_size(self):
507
"""Return the recommended page size for this transport.
509
This is potentially different for every path in a given namespace.
510
For example, local transports might use an operating system call to
511
get the block size for a given path, which can vary due to mount
514
:return: The page size in bytes.
463
518
def relpath(self, abspath):
464
519
"""Return the local path portion from a given absolute path.
693
748
yield self.get(relpath)
696
@deprecated_method(zero_eleven)
697
def put(self, relpath, f, mode=None):
698
"""Copy the file-like object into the location.
700
:param relpath: Location to put the contents, relative to base.
701
:param f: File-like object.
702
:param mode: The mode for the newly created file,
703
None means just use the default
705
if isinstance(f, str):
706
return self.put_bytes(relpath, f, mode=mode)
708
return self.put_file(relpath, f, mode=mode)
710
751
def put_bytes(self, relpath, bytes, mode=None):
711
752
"""Atomically put the supplied bytes into the given location.
794
835
self.mkdir(parent_dir, mode=dir_mode)
795
836
return self.put_file(relpath, f, mode=mode)
797
@deprecated_method(zero_eleven)
798
def put_multi(self, files, mode=None, pb=None):
799
"""Put a set of files into the location.
801
:param files: A list of tuples of relpath, file object [(path1, file1), (path2, file2),...]
802
:param pb: An optional ProgressBar for indicating percent done.
803
:param mode: The mode for the newly created files
804
:return: The number of files copied.
807
if isinstance(f, str):
808
self.put_bytes(path, f, mode=mode)
810
self.put_file(path, f, mode=mode)
811
return len(self._iterate_over(files, _put, pb, 'put', expand=True))
813
838
def mkdir(self, relpath, mode=None):
814
839
"""Create a directory at the given path."""
815
840
raise NotImplementedError(self.mkdir)
820
845
self.mkdir(path, mode=mode)
821
846
return len(self._iterate_over(relpaths, mkdir, pb, 'mkdir', expand=False))
823
@deprecated_method(zero_eleven)
824
def append(self, relpath, f, mode=None):
825
"""Append the text in the file-like object to the supplied location.
827
returns the length of relpath before the content was written to it.
829
If the file does not exist, it is created with the supplied mode.
848
def open_write_stream(self, relpath, mode=None):
849
"""Open a writable file stream at relpath.
851
A file stream is a file like object with a write() method that accepts
852
bytes to write.. Buffering may occur internally until the stream is
853
closed with stream.close(). Calls to readv or the get_* methods will
854
be synchronised with any internal buffering that may be present.
856
:param relpath: The relative path to the file.
857
:param mode: The mode for the newly created file,
858
None means just use the default
859
:return: A FileStream. FileStream objects have two methods, write() and
860
close(). There is no guarantee that data is committed to the file
861
if close() has not been called (even if get() is called on the same
831
return self.append_file(relpath, f, mode=mode)
864
raise NotImplementedError(self.open_write_stream)
833
866
def append_file(self, relpath, f, mode=None):
834
867
"""Append bytes from a file-like object to a file at relpath.
1437
1470
'URLs must be properly escaped (protocol: %s)')
1439
1472
transport = None
1440
if possible_transports:
1473
if possible_transports is not None:
1441
1474
for t in possible_transports:
1442
1475
t_same_connection = t._reuse_for(base)
1443
1476
if t_same_connection is not None:
1450
1483
if proto is not None and base.startswith(proto):
1451
1484
transport, last_err = _try_transport_factories(base, factory_list)
1453
if possible_transports:
1486
if possible_transports is not None:
1454
1487
assert transport not in possible_transports
1455
1488
possible_transports.append(transport)
1456
1489
return transport