/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

Merge bzr.dev,

Show diffs side-by-side

added added

removed removed

Lines of Context:
165
165
            port = int(port)
166
166
        except ValueError:
167
167
            # TODO: Should this be ConnectionError?
168
 
            raise errors.TransportError('%s: invalid port number' % port)
 
168
            raise errors.TransportError(
 
169
                'invalid port number %s in url:\n%s' % (port, url))
169
170
    host = urllib.unquote(host)
170
171
 
171
172
    path = urllib.unquote(path)
198
199
    implementations can do pipelining.
199
200
    In general implementations should support having a generator or a list
200
201
    as an argument (ie always iterate, never index)
 
202
 
 
203
    :ivar base: Base URL for the transport; should always end in a slash.
201
204
    """
202
205
 
203
206
    # implementations can override this if it is more efficient
220
223
 
221
224
        This handles things like ENOENT, ENOTDIR, EEXIST, and EACCESS
222
225
        """
223
 
        if hasattr(e, 'errno'):
 
226
        if getattr(e, 'errno', None) is not None:
224
227
            if e.errno in (errno.ENOENT, errno.ENOTDIR):
225
228
                raise errors.NoSuchFile(path, extra=e)
226
229
            # I would rather use errno.EFOO, but there doesn't seem to be
304
307
 
305
308
    def abspath(self, relpath):
306
309
        """Return the full url to the given relative path.
307
 
        This can be supplied with a string or a list
308
310
 
309
 
        XXX: Robert Collins 20051016 - is this really needed in the public
310
 
             interface ?
 
311
        :param relpath: a string of a relative path
311
312
        """
 
313
 
 
314
        # XXX: Robert Collins 20051016 - is this really needed in the public
 
315
        # interface ?
312
316
        raise NotImplementedError(self.abspath)
313
317
 
 
318
    def _combine_paths(self, base_path, relpath):
 
319
        """Transform a Transport-relative path to a remote absolute path.
 
320
 
 
321
        This does not handle substitution of ~ but does handle '..' and '.'
 
322
        components.
 
323
 
 
324
        Examples::
 
325
 
 
326
            >>> t = Transport('/')
 
327
            >>> t._combine_paths('/home/sarah', 'project/foo')
 
328
            '/home/sarah/project/foo'
 
329
            >>> t._combine_paths('/home/sarah', '../../etc')
 
330
            '/etc'
 
331
 
 
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.
 
336
        """
 
337
        # FIXME: share the common code across more transports; variants of
 
338
        # this likely occur in http and sftp too.
 
339
        #
 
340
        # TODO: Also need to consider handling of ~, which might vary between
 
341
        # transports?
 
342
        if not isinstance(relpath, str):
 
343
            raise errors.InvalidURL("not a valid url: %r" % relpath)
 
344
        if relpath.startswith('/'):
 
345
            base_parts = []
 
346
        else:
 
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('/'):
 
351
            if p == '..':
 
352
                if len(base_parts) == 0:
 
353
                    # In most filesystems, a request for the parent
 
354
                    # of root, just returns root.
 
355
                    continue
 
356
                base_parts.pop()
 
357
            elif p == '.':
 
358
                continue # No-op
 
359
            elif p != '':
 
360
                base_parts.append(p)
 
361
        path = '/'.join(base_parts)
 
362
        return path
 
363
 
314
364
    def relpath(self, abspath):
315
365
        """Return the local path portion from a given absolute path.
316
366
 
342
392
        Note that some transports MAY allow querying on directories, but this
343
393
        is not part of the protocol.  In other words, the results of 
344
394
        t.has("a_directory_name") are undefined.
 
395
 
 
396
        :rtype: bool
345
397
        """
346
398
        raise NotImplementedError(self.has)
347
399
 
378
430
        """Get the file at the given relative path.
379
431
 
380
432
        :param relpath: The relative path to the file
 
433
        :rtype: File-like object.
381
434
        """
382
435
        raise NotImplementedError(self.get)
383
436
 
388
441
        """
389
442
        return self.get(relpath).read()
390
443
 
 
444
    def get_smart_client(self):
 
445
        """Return a smart client for this transport if possible.
 
446
 
 
447
        :raises NoSmartServer: if no smart server client is available.
 
448
        """
 
449
        raise errors.NoSmartServer(self.base)
 
450
 
391
451
    def readv(self, relpath, offsets):
392
452
        """Get parts of the file at the given relative path.
393
453
 
398
458
            return
399
459
 
400
460
        fp = self.get(relpath)
401
 
        return self._seek_and_read(fp, offsets)
 
461
        return self._seek_and_read(fp, offsets, relpath)
402
462
 
403
 
    def _seek_and_read(self, fp, offsets):
 
463
    def _seek_and_read(self, fp, offsets, relpath='<unknown>'):
404
464
        """An implementation of readv that uses fp.seek and fp.read.
405
465
 
406
466
        This uses _coalesce_offsets to issue larger reads and fewer seeks.
428
488
            #       benchmarked.
429
489
            fp.seek(c_offset.start)
430
490
            data = fp.read(c_offset.length)
 
491
            if len(data) < c_offset.length:
 
492
                raise errors.ShortReadvError(relpath, c_offset.start,
 
493
                            c_offset.length, actual=len(data))
431
494
            for suboffset, subsize in c_offset.ranges:
432
495
                key = (c_offset.start+suboffset, subsize)
433
496
                data_map[key] = data[suboffset:suboffset+subsize]
634
697
        return self.append_file(relpath, f, mode=mode)
635
698
 
636
699
    def append_file(self, relpath, f, mode=None):
637
 
        """Append the text in the file-like object to the supplied location.
638
 
 
639
 
        returns the length of relpath before the content was written to it.
640
 
        
641
 
        If the file does not exist, it is created with the supplied mode.
 
700
        """Append bytes from a file-like object to a file at relpath.
 
701
 
 
702
        The file is created if it does not already exist.
 
703
 
 
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
 
706
            existing files.
 
707
 
 
708
        :returns: the length of relpath before the content was written to it.
642
709
        """
643
710
        symbol_versioning.warn('Transport %s should implement append_file,'
644
711
                               ' rather than implementing append() as of'
648
715
        return self.append(relpath, f, mode=mode)
649
716
 
650
717
    def append_bytes(self, relpath, bytes, mode=None):
651
 
        """Append the text in the string object to the supplied location.
652
 
 
653
 
        returns the length of relpath before the content was written to it.
654
 
        
655
 
        If the file does not exist, it is created with the supplied mode.
 
718
        """Append bytes to a file at relpath.
 
719
 
 
720
        The file is created if it does not already exist.
 
721
 
 
722
        :type f: str
 
723
        :param f: a string of the bytes to append.
 
724
        :param mode: Unix mode for newly created files.  This is not used for
 
725
            existing files.
 
726
 
 
727
        :returns: the length of relpath before the content was written to it.
656
728
        """
657
729
        assert isinstance(bytes, str), \
658
730
            'bytes must be a plain string, not %s' % type(bytes)
848
920
        WARNING: many transports do not support this, so trying avoid using
849
921
        it if at all possible.
850
922
        """
851
 
        raise errors.TransportNotPossible("This transport has not "
 
923
        raise errors.TransportNotPossible("Transport %r has not "
852
924
                                          "implemented list_dir "
853
925
                                          "(but must claim to be listable "
854
 
                                          "to trigger this error).")
 
926
                                          "to trigger this error)."
 
927
                                          % (self))
855
928
 
856
929
    def lock_read(self, relpath):
857
930
        """Lock the given file for shared (read) access.
858
 
        WARNING: many transports do not support this, so trying avoid using it
 
931
 
 
932
        WARNING: many transports do not support this, so trying avoid using it.
 
933
        These methods may be removed in the future.
 
934
 
 
935
        Transports may raise TransportNotPossible if OS-level locks cannot be
 
936
        taken over this transport.  
859
937
 
860
938
        :return: A lock object, which should contain an unlock() function.
861
939
        """
862
 
        raise NotImplementedError(self.lock_read)
 
940
        raise errors.TransportNotPossible("transport locks not supported on %s" % self)
863
941
 
864
942
    def lock_write(self, relpath):
865
943
        """Lock the given file for exclusive (write) access.
866
 
        WARNING: many transports do not support this, so trying avoid using it
 
944
 
 
945
        WARNING: many transports do not support this, so trying avoid using it.
 
946
        These methods may be removed in the future.
 
947
 
 
948
        Transports may raise TransportNotPossible if OS-level locks cannot be
 
949
        taken over this transport.
867
950
 
868
951
        :return: A lock object, which should contain an unlock() function.
869
952
        """
870
 
        raise NotImplementedError(self.lock_write)
 
953
        raise errors.TransportNotPossible("transport locks not supported on %s" % self)
871
954
 
872
955
    def is_readonly(self):
873
956
        """Return true if this connection cannot be written to."""
1015
1098
 
1016
1099
    def get_transport_test_permutations(self, module):
1017
1100
        """Get the permutations module wants to have tested."""
1018
 
        if not hasattr(module, 'get_test_permutations'):
 
1101
        if getattr(module, 'get_test_permutations', None) is None:
1019
1102
            warning("transport module %s doesn't provide get_test_permutations()"
1020
1103
                    % module.__name__)
1021
1104
            return []
1083
1166
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
1084
1167
register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator')
1085
1168
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
1086
 
register_lazy_transport('vfat+', 
 
1169
register_lazy_transport('vfat+',
1087
1170
                        'bzrlib.transport.fakevfat',
1088
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')