297
308
def abspath(self, relpath):
298
309
"""Return the full url to the given relative path.
299
This can be supplied with a string or a list
301
XXX: Robert Collins 20051016 - is this really needed in the public
311
:param relpath: a string of a relative path
314
# XXX: Robert Collins 20051016 - is this really needed in the public
304
316
raise NotImplementedError(self.abspath)
318
def _combine_paths(self, base_path, relpath):
319
"""Transform a Transport-relative path to a remote absolute path.
321
This does not handle substitution of ~ but does handle '..' and '.'
326
>>> t = Transport('/')
327
>>> t._combine_paths('/home/sarah', 'project/foo')
328
'/home/sarah/project/foo'
329
>>> t._combine_paths('/home/sarah', '../../etc')
332
:param base_path: urlencoded path for the transport root; typically a
333
URL but need not contain scheme/host/etc.
334
:param relpath: relative url string for relative part of remote path.
335
:return: urlencoded string for final path.
337
# FIXME: share the common code across more transports; variants of
338
# this likely occur in http and sftp too.
340
# TODO: Also need to consider handling of ~, which might vary between
342
if not isinstance(relpath, str):
343
raise errors.InvalidURL("not a valid url: %r" % relpath)
344
if relpath.startswith('/'):
347
base_parts = base_path.split('/')
348
if len(base_parts) > 0 and base_parts[-1] == '':
349
base_parts = base_parts[:-1]
350
for p in relpath.split('/'):
352
if len(base_parts) == 0:
353
# In most filesystems, a request for the parent
354
# of root, just returns root.
361
path = '/'.join(base_parts)
306
364
def relpath(self, abspath):
307
365
"""Return the local path portion from a given absolute path.
483
561
yield self.get(relpath)
564
@deprecated_method(zero_eleven)
486
565
def put(self, relpath, f, mode=None):
487
"""Copy the file-like or string object into the location.
566
"""Copy the file-like object into the location.
489
568
:param relpath: Location to put the contents, relative to base.
490
:param f: File-like or string object.
569
:param f: File-like object.
491
570
:param mode: The mode for the newly created file,
492
571
None means just use the default
494
raise NotImplementedError(self.put)
573
if isinstance(f, str):
574
return self.put_bytes(relpath, f, mode=mode)
576
return self.put_file(relpath, f, mode=mode)
578
def put_bytes(self, relpath, bytes, mode=None):
579
"""Atomically put the supplied bytes into the given location.
581
:param relpath: The location to put the contents, relative to the
583
:param bytes: A bytestring of data.
584
:param mode: Create the file with the given mode.
587
assert isinstance(bytes, str), \
588
'bytes must be a plain string, not %s' % type(bytes)
589
return self.put_file(relpath, StringIO(bytes), mode=mode)
591
def put_bytes_non_atomic(self, relpath, bytes, mode=None,
592
create_parent_dir=False,
594
"""Copy the string into the target location.
596
This function is not strictly safe to use. See
597
Transport.put_bytes_non_atomic for more information.
599
:param relpath: The remote location to put the contents.
600
:param bytes: A string object containing the raw bytes to write into
602
:param mode: Possible access permissions for new file.
603
None means do not set remote permissions.
604
:param create_parent_dir: If we cannot create the target file because
605
the parent directory does not exist, go ahead and
606
create it, and then try again.
607
:param dir_mode: Possible access permissions for new directories.
609
assert isinstance(bytes, str), \
610
'bytes must be a plain string, not %s' % type(bytes)
611
self.put_file_non_atomic(relpath, StringIO(bytes), mode=mode,
612
create_parent_dir=create_parent_dir,
615
def put_file(self, relpath, f, mode=None):
616
"""Copy the file-like object into the location.
618
:param relpath: Location to put the contents, relative to base.
619
:param f: File-like object.
620
:param mode: The mode for the newly created file,
621
None means just use the default.
623
# We would like to mark this as NotImplemented, but most likely
624
# transports have defined it in terms of the old api.
625
symbol_versioning.warn('Transport %s should implement put_file,'
626
' rather than implementing put() as of'
628
% (self.__class__.__name__,),
630
return self.put(relpath, f, mode=mode)
631
#raise NotImplementedError(self.put_file)
633
def put_file_non_atomic(self, relpath, f, mode=None,
634
create_parent_dir=False,
636
"""Copy the file-like object into the target location.
638
This function is not strictly safe to use. It is only meant to
639
be used when you already know that the target does not exist.
640
It is not safe, because it will open and truncate the remote
641
file. So there may be a time when the file has invalid contents.
643
:param relpath: The remote location to put the contents.
644
:param f: File-like object.
645
:param mode: Possible access permissions for new file.
646
None means do not set remote permissions.
647
:param create_parent_dir: If we cannot create the target file because
648
the parent directory does not exist, go ahead and
649
create it, and then try again.
650
:param dir_mode: Possible access permissions for new directories.
652
# Default implementation just does an atomic put.
654
return self.put_file(relpath, f, mode=mode)
655
except errors.NoSuchFile:
656
if not create_parent_dir:
658
parent_dir = osutils.dirname(relpath)
660
self.mkdir(parent_dir, mode=dir_mode)
661
return self.put_file(relpath, f, mode=mode)
663
@deprecated_method(zero_eleven)
496
664
def put_multi(self, files, mode=None, pb=None):
497
665
"""Put a set of files into the location.
515
686
self.mkdir(path, mode=mode)
516
687
return len(self._iterate_over(relpaths, mkdir, pb, 'mkdir', expand=False))
689
@deprecated_method(zero_eleven)
518
690
def append(self, relpath, f, mode=None):
519
"""Append the text in the file-like or string object to
520
the supplied location.
691
"""Append the text in the file-like object to the supplied location.
522
returns the length of f before the content was written to it.
693
returns the length of relpath before the content was written to it.
524
695
If the file does not exist, it is created with the supplied mode.
526
raise NotImplementedError(self.append)
697
return self.append_file(relpath, f, mode=mode)
699
def append_file(self, relpath, f, mode=None):
700
"""Append bytes from a file-like object to a file at relpath.
702
The file is created if it does not already exist.
704
:param f: a file-like object of the bytes to append.
705
:param mode: Unix mode for newly created files. This is not used for
708
:returns: the length of relpath before the content was written to it.
710
symbol_versioning.warn('Transport %s should implement append_file,'
711
' rather than implementing append() as of'
713
% (self.__class__.__name__,),
715
return self.append(relpath, f, mode=mode)
717
def append_bytes(self, relpath, bytes, mode=None):
718
"""Append bytes to a file at relpath.
720
The file is created if it does not already exist.
723
:param f: a string of the bytes to append.
724
:param mode: Unix mode for newly created files. This is not used for
727
:returns: the length of relpath before the content was written to it.
729
assert isinstance(bytes, str), \
730
'bytes must be a plain string, not %s' % type(bytes)
731
return self.append_file(relpath, StringIO(bytes), mode=mode)
528
733
def append_multi(self, files, pb=None):
529
734
"""Append the text in each file-like or string object to
715
920
WARNING: many transports do not support this, so trying avoid using
716
921
it if at all possible.
718
raise errors.TransportNotPossible("This transport has not "
923
raise errors.TransportNotPossible("Transport %r has not "
719
924
"implemented list_dir "
720
925
"(but must claim to be listable "
721
"to trigger this error).")
926
"to trigger this error)."
723
929
def lock_read(self, relpath):
724
930
"""Lock the given file for shared (read) access.
725
WARNING: many transports do not support this, so trying avoid using it
932
WARNING: many transports do not support this, so trying avoid using it.
933
These methods may be removed in the future.
935
Transports may raise TransportNotPossible if OS-level locks cannot be
936
taken over this transport.
727
938
:return: A lock object, which should contain an unlock() function.
729
raise NotImplementedError(self.lock_read)
940
raise errors.TransportNotPossible("transport locks not supported on %s" % self)
731
942
def lock_write(self, relpath):
732
943
"""Lock the given file for exclusive (write) access.
733
WARNING: many transports do not support this, so trying avoid using it
945
WARNING: many transports do not support this, so trying avoid using it.
946
These methods may be removed in the future.
948
Transports may raise TransportNotPossible if OS-level locks cannot be
949
taken over this transport.
735
951
:return: A lock object, which should contain an unlock() function.
737
raise NotImplementedError(self.lock_write)
953
raise errors.TransportNotPossible("transport locks not supported on %s" % self)
739
955
def is_readonly(self):
740
956
"""Return true if this connection cannot be written to."""
950
1166
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
951
1167
register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator')
952
1168
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
953
register_lazy_transport('vfat+',
1169
register_lazy_transport('vfat+',
954
1170
'bzrlib.transport.fakevfat',
955
1171
'FakeVFATTransportDecorator')
1172
register_lazy_transport('bzr://',
1173
'bzrlib.transport.smart',
1174
'SmartTCPTransport')
1175
register_lazy_transport('bzr+ssh://',
1176
'bzrlib.transport.smart',
1177
'SmartSSHTransport')