/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

  • Committer: Martin von Gagern
  • Date: 2010-04-20 08:47:38 UTC
  • mfrom: (5167 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5195.
  • Revision ID: martin.vgagern@gmx.net-20100420084738-ygymnqmdllzrhpfn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Transport is an abstraction layer to handle file access.
18
18
 
41
41
    errors,
42
42
    osutils,
43
43
    symbol_versioning,
 
44
    ui,
44
45
    urlutils,
45
46
    )
46
47
""")
49
50
        deprecated_method,
50
51
        deprecated_function,
51
52
        DEPRECATED_PARAMETER,
52
 
        one_four,
53
53
        )
54
54
from bzrlib.trace import (
55
55
    mutter,
84
84
def _get_transport_modules():
85
85
    """Return a list of the modules providing transports."""
86
86
    modules = set()
87
 
    for prefix, factory_list in transport_list_registry.iteritems():
 
87
    for prefix, factory_list in transport_list_registry.items():
88
88
        for factory in factory_list:
89
89
            if hasattr(factory, "_module_name"):
90
90
                modules.add(factory._module_name)
91
91
            else:
92
92
                modules.add(factory._obj.__module__)
93
 
    # Add chroot directly, because there is no handler registered for it.
 
93
    # Add chroot and pathfilter directly, because there is no handler
 
94
    # registered for it.
94
95
    modules.add('bzrlib.transport.chroot')
 
96
    modules.add('bzrlib.transport.pathfilter')
95
97
    result = list(modules)
96
98
    result.sort()
97
99
    return result
100
102
class TransportListRegistry(registry.Registry):
101
103
    """A registry which simplifies tracking available Transports.
102
104
 
103
 
    A registration of a new protocol requires two step:
 
105
    A registration of a new protocol requires two steps:
104
106
    1) register the prefix with the function register_transport( )
105
107
    2) register the protocol provider with the function
106
108
    register_transport_provider( ) ( and the "lazy" variant )
107
109
 
108
110
    This is needed because:
109
 
    a) a single provider can support multple protcol ( like the ftp
 
111
    a) a single provider can support multiple protocols ( like the ftp
110
112
    provider which supports both the ftp:// and the aftp:// protocols )
111
113
    b) a single protocol can have multiple providers ( like the http://
112
114
    protocol which is supported by both the urllib and pycurl provider )
242
244
 
243
245
class FileFileStream(FileStream):
244
246
    """A file stream object returned by open_write_stream.
245
 
    
 
247
 
246
248
    This version uses a file like object to perform writes.
247
249
    """
248
250
 
259
261
 
260
262
class AppendBasedFileStream(FileStream):
261
263
    """A file stream object returned by open_write_stream.
262
 
    
 
264
 
263
265
    This version uses append on a transport to perform writes.
264
266
    """
265
267
 
272
274
    from/to a storage location.
273
275
 
274
276
    Most functions have a _multi variant, which allows you to queue up
275
 
    multiple requests. They generally have a dumb base implementation 
 
277
    multiple requests. They generally have a dumb base implementation
276
278
    which just iterates over the arguments, but smart Transport
277
279
    implementations can do pipelining.
278
280
    In general implementations should support having a generator or a list
323
325
 
324
326
    def clone(self, offset=None):
325
327
        """Return a new Transport object, cloned from the current location,
326
 
        using a subdirectory or parent directory. This allows connections 
 
328
        using a subdirectory or parent directory. This allows connections
327
329
        to be pooled, rather than a new one needed for each subdir.
328
330
        """
329
331
        raise NotImplementedError(self.clone)
330
332
 
 
333
    def create_prefix(self):
 
334
        """Create all the directories leading down to self.base."""
 
335
        cur_transport = self
 
336
        needed = [cur_transport]
 
337
        # Recurse upwards until we can create a directory successfully
 
338
        while True:
 
339
            new_transport = cur_transport.clone('..')
 
340
            if new_transport.base == cur_transport.base:
 
341
                raise errors.BzrCommandError(
 
342
                    "Failed to create path prefix for %s."
 
343
                    % cur_transport.base)
 
344
            try:
 
345
                new_transport.mkdir('.')
 
346
            except errors.NoSuchFile:
 
347
                needed.append(new_transport)
 
348
                cur_transport = new_transport
 
349
            except errors.FileExists:
 
350
                break
 
351
            else:
 
352
                break
 
353
        # Now we only need to create child directories
 
354
        while needed:
 
355
            cur_transport = needed.pop()
 
356
            cur_transport.ensure_base()
 
357
 
331
358
    def ensure_base(self):
332
359
        """Ensure that the directory this transport references exists.
333
360
 
367
394
        raise NotImplementedError(self.external_url)
368
395
 
369
396
    def _pump(self, from_file, to_file):
370
 
        """Most children will need to copy from one file-like 
 
397
        """Most children will need to copy from one file-like
371
398
        object or string to another one.
372
399
        This just gives them something easy to call.
373
400
        """
382
409
        except TypeError: # We can't tell how many, because relpaths is a generator
383
410
            return None
384
411
 
 
412
    def _report_activity(self, bytes, direction):
 
413
        """Notify that this transport has activity.
 
414
 
 
415
        Implementations should call this from all methods that actually do IO.
 
416
        Be careful that it's not called twice, if one method is implemented on
 
417
        top of another.
 
418
 
 
419
        :param bytes: Number of bytes read or written.
 
420
        :param direction: 'read' or 'write' or None.
 
421
        """
 
422
        ui.ui_factory.report_transport_activity(self, bytes, direction)
 
423
 
385
424
    def _update_pb(self, pb, msg, count, total):
386
425
        """Update the progress bar based on the current count
387
426
        and total available, total may be None if it was
439
478
            t._combine_paths('/home/sarah', '/etc')
440
479
                => '/etc'
441
480
 
442
 
        :param base_path: urlencoded path for the transport root; typically a 
 
481
        :param base_path: urlencoded path for the transport root; typically a
443
482
             URL but need not contain scheme/host/etc.
444
483
        :param relpath: relative url string for relative part of remote path.
445
484
        :return: urlencoded string for final path.
472
511
        """Return the recommended page size for this transport.
473
512
 
474
513
        This is potentially different for every path in a given namespace.
475
 
        For example, local transports might use an operating system call to 
 
514
        For example, local transports might use an operating system call to
476
515
        get the block size for a given path, which can vary due to mount
477
516
        points.
478
517
 
484
523
        """Return the local path portion from a given absolute path.
485
524
 
486
525
        This default implementation is not suitable for filesystems with
487
 
        aliasing, such as that given by symlinks, where a path may not 
488
 
        start with our base, but still be a relpath once aliasing is 
 
526
        aliasing, such as that given by symlinks, where a path may not
 
527
        start with our base, but still be a relpath once aliasing is
489
528
        resolved.
490
529
        """
491
530
        # TODO: This might want to use bzrlib.osutils.relpath
503
542
        """
504
543
        raise errors.NotLocalUrl(self.abspath(relpath))
505
544
 
506
 
 
507
545
    def has(self, relpath):
508
546
        """Does the file relpath exist?
509
 
        
 
547
 
510
548
        Note that some transports MAY allow querying on directories, but this
511
 
        is not part of the protocol.  In other words, the results of 
 
549
        is not part of the protocol.  In other words, the results of
512
550
        t.has("a_directory_name") are undefined.
513
551
 
514
552
        :rtype: bool
535
573
        """Iter the relative paths of files in the transports sub-tree.
536
574
 
537
575
        *NOTE*: This only lists *files*, not subdirectories!
538
 
        
 
576
 
539
577
        As with other listing functions, only some transports implement this,.
540
578
        you may check via listable() to determine if it will.
541
579
        """
568
606
 
569
607
        :param relpath: The relative path to the file
570
608
        """
571
 
        return self.get(relpath).read()
572
 
 
573
 
    @deprecated_method(one_four)
574
 
    def get_smart_client(self):
575
 
        """Return a smart client for this transport if possible.
576
 
 
577
 
        A smart client doesn't imply the presence of a smart server: it implies
578
 
        that the smart protocol can be tunnelled via this transport.
579
 
 
580
 
        :raises NoSmartServer: if no smart server client is available.
581
 
        """
582
 
        raise errors.NoSmartServer(self.base)
 
609
        f = self.get(relpath)
 
610
        try:
 
611
            return f.read()
 
612
        finally:
 
613
            f.close()
583
614
 
584
615
    def get_smart_medium(self):
585
616
        """Return a smart client medium for this transport if possible.
591
622
        """
592
623
        raise errors.NoSmartMedium(self)
593
624
 
594
 
    @deprecated_method(one_four)
595
 
    def get_shared_medium(self):
596
 
        """Return a smart client shared medium for this transport if possible.
597
 
 
598
 
        A smart medium doesn't imply the presence of a smart server: it implies
599
 
        that the smart protocol can be tunnelled via this transport.
600
 
 
601
 
        :raises NoSmartMedium: if no smart server medium is available.
602
 
        """
603
 
        raise errors.NoSmartMedium(self)
604
 
 
605
625
    def readv(self, relpath, offsets, adjust_for_latency=False,
606
626
        upper_limit=None):
607
627
        """Get parts of the file at the given relative path.
673
693
        # Cache the results, but only until they have been fulfilled
674
694
        data_map = {}
675
695
        for c_offset in coalesced:
676
 
            # TODO: jam 20060724 it might be faster to not issue seek if 
 
696
            # TODO: jam 20060724 it might be faster to not issue seek if
677
697
            #       we are already at the right location. This should be
678
698
            #       benchmarked.
679
699
            fp.seek(c_offset.start)
688
708
            # Now that we've read some data, see if we can yield anything back
689
709
            while cur_offset_and_size in data_map:
690
710
                this_data = data_map.pop(cur_offset_and_size)
691
 
                yield cur_offset_and_size[0], this_data
692
 
                cur_offset_and_size = offset_stack.next()
 
711
                this_offset = cur_offset_and_size[0]
 
712
                try:
 
713
                    cur_offset_and_size = offset_stack.next()
 
714
                except StopIteration:
 
715
                    # Close the file handle as there will be no more data
 
716
                    # The handle would normally be cleaned up as this code goes
 
717
                    # out of scope, but as we are a generator, not all code
 
718
                    # will re-enter once we have consumed all the expected
 
719
                    # data. For example:
 
720
                    #   zip(range(len(requests)), readv(foo, requests))
 
721
                    # Will stop because the range is done, and not run the
 
722
                    # cleanup code for the readv().
 
723
                    fp.close()
 
724
                    cur_offset_and_size = None
 
725
                yield this_offset, this_data
693
726
 
694
727
    def _sort_expand_and_combine(self, offsets, upper_limit):
695
728
        """Helper for readv.
784
817
        cur = _CoalescedOffset(None, None, [])
785
818
        coalesced_offsets = []
786
819
 
 
820
        if max_size <= 0:
 
821
            # 'unlimited', but we actually take this to mean 100MB buffer limit
 
822
            max_size = 100*1024*1024
 
823
 
787
824
        for start, size in offsets:
788
825
            end = start + size
789
826
            if (last_end is not None
811
848
        """Get a list of file-like objects, one for each entry in relpaths.
812
849
 
813
850
        :param relpaths: A list of relative paths.
814
 
        :param pb:  An optional ProgressBar for indicating percent done.
 
851
        :param pb:  An optional ProgressTask for indicating percent done.
815
852
        :return: A list or generator of file-like objects
816
853
        """
817
854
        # TODO: Consider having this actually buffer the requests,
843
880
                             dir_mode=None):
844
881
        """Copy the string into the target location.
845
882
 
846
 
        This function is not strictly safe to use. See 
 
883
        This function is not strictly safe to use. See
847
884
        Transport.put_bytes_non_atomic for more information.
848
885
 
849
886
        :param relpath: The remote location to put the contents.
931
968
        be synchronised with any internal buffering that may be present.
932
969
 
933
970
        :param relpath: The relative path to the file.
934
 
        :param mode: The mode for the newly created file, 
 
971
        :param mode: The mode for the newly created file,
935
972
                     None means just use the default
936
973
        :return: A FileStream. FileStream objects have two methods, write() and
937
974
            close(). There is no guarantee that data is committed to the file
980
1017
        the supplied location.
981
1018
 
982
1019
        :param files: A set of (path, f) entries
983
 
        :param pb:  An optional ProgressBar for indicating percent done.
 
1020
        :param pb:  An optional ProgressTask for indicating percent done.
984
1021
        """
985
1022
        return self._iterate_over(files, self.append_file, pb, 'append', expand=True)
986
1023
 
987
1024
    def copy(self, rel_from, rel_to):
988
1025
        """Copy the item at rel_from to the location at rel_to.
989
 
        
990
 
        Override this for efficiency if a specific transport can do it 
 
1026
 
 
1027
        Override this for efficiency if a specific transport can do it
991
1028
        faster than this default implementation.
992
1029
        """
993
1030
        self.put_file(rel_to, self.get(rel_from))
994
1031
 
995
1032
    def copy_multi(self, relpaths, pb=None):
996
1033
        """Copy a bunch of entries.
997
 
        
 
1034
 
998
1035
        :param relpaths: A list of tuples of the form [(from, to), (from, to),...]
999
1036
        """
1000
1037
        # This is the non-pipelined implementation, so that
1018
1055
    def copy_tree(self, from_relpath, to_relpath):
1019
1056
        """Copy a subtree from one relpath to another.
1020
1057
 
1021
 
        If a faster implementation is available, specific transports should 
 
1058
        If a faster implementation is available, specific transports should
1022
1059
        implement it.
1023
1060
        """
1024
1061
        source = self.clone(from_relpath)
1025
 
        self.mkdir(to_relpath)
1026
1062
        target = self.clone(to_relpath)
 
1063
 
 
1064
        # create target directory with the same rwx bits as source.
 
1065
        # use mask to ensure that bits other than rwx are ignored.
 
1066
        stat = self.stat(from_relpath)
 
1067
        target.mkdir('.', stat.st_mode & 0777)
 
1068
        source.copy_tree_to_transport(target)
 
1069
 
 
1070
    def copy_tree_to_transport(self, to_transport):
 
1071
        """Copy a subtree from one transport to another.
 
1072
 
 
1073
        self.base is used as the source tree root, and to_transport.base
 
1074
        is used as the target.  to_transport.base must exist (and be a
 
1075
        directory).
 
1076
        """
1027
1077
        files = []
1028
1078
        directories = ['.']
1029
1079
        while directories:
1030
1080
            dir = directories.pop()
1031
1081
            if dir != '.':
1032
 
                target.mkdir(dir)
1033
 
            for path in source.list_dir(dir):
 
1082
                to_transport.mkdir(dir)
 
1083
            for path in self.list_dir(dir):
1034
1084
                path = dir + '/' + path
1035
 
                stat = source.stat(path)
 
1085
                stat = self.stat(path)
1036
1086
                if S_ISDIR(stat.st_mode):
1037
1087
                    directories.append(path)
1038
1088
                else:
1039
1089
                    files.append(path)
1040
 
        source.copy_to(files, target)
 
1090
        self.copy_to(files, to_transport)
1041
1091
 
1042
1092
    def rename(self, rel_from, rel_to):
1043
1093
        """Rename a file or directory.
1063
1113
 
1064
1114
        The destination is deleted if possible, even if it's a non-empty
1065
1115
        directory tree.
1066
 
        
 
1116
 
1067
1117
        If a transport can directly implement this it is suggested that
1068
1118
        it do so for efficiency.
1069
1119
        """
1076
1126
 
1077
1127
    def move_multi(self, relpaths, pb=None):
1078
1128
        """Move a bunch of entries.
1079
 
        
 
1129
 
1080
1130
        :param relpaths: A list of tuples of the form [(from1, to1), (from2, to2),...]
1081
1131
        """
1082
1132
        return self._iterate_over(relpaths, self.move, pb, 'move', expand=True)
1135
1185
        NOTE: This returns an object with fields such as 'st_size'. It MAY
1136
1186
        or MAY NOT return the literal result of an os.stat() call, so all
1137
1187
        access should be via named fields.
1138
 
        ALSO NOTE: Stats of directories may not be supported on some 
 
1188
        ALSO NOTE: Stats of directories may not be supported on some
1139
1189
        transports.
1140
1190
        """
1141
1191
        raise NotImplementedError(self.stat)
1156
1206
        count = self._iterate_over(relpaths, gather, pb, 'stat', expand=False)
1157
1207
        return stats
1158
1208
 
 
1209
    def readlink(self, relpath):
 
1210
        """Return a string representing the path to which the symbolic link points."""
 
1211
        raise errors.TransportNotPossible("Dereferencing symlinks is not supported on %s" % self)
 
1212
 
 
1213
    def hardlink(self, source, link_name):
 
1214
        """Create a hardlink pointing to source named link_name."""
 
1215
        raise errors.TransportNotPossible("Hard links are not supported on %s" % self)
 
1216
 
 
1217
    def symlink(self, source, link_name):
 
1218
        """Create a symlink pointing to source named link_name."""
 
1219
        raise errors.TransportNotPossible("Symlinks are not supported on %s" % self)
 
1220
 
1159
1221
    def listable(self):
1160
1222
        """Return True if this store supports listing."""
1161
1223
        raise NotImplementedError(self.listable)
1178
1240
        These methods may be removed in the future.
1179
1241
 
1180
1242
        Transports may raise TransportNotPossible if OS-level locks cannot be
1181
 
        taken over this transport.  
 
1243
        taken over this transport.
1182
1244
 
1183
1245
        :return: A lock object, which should contain an unlock() function.
1184
1246
        """
1205
1267
        """Return true if this transport can store and retrieve unix modebits.
1206
1268
 
1207
1269
        (For example, 0700 to make a directory owner-private.)
1208
 
        
1209
 
        Note: most callers will not want to switch on this, but should rather 
 
1270
 
 
1271
        Note: most callers will not want to switch on this, but should rather
1210
1272
        just try and set permissions and let them be either stored or not.
1211
1273
        This is intended mainly for the use of the test suite.
1212
 
        
1213
 
        Warning: this is not guaranteed to be accurate as sometimes we can't 
 
1274
 
 
1275
        Warning: this is not guaranteed to be accurate as sometimes we can't
1214
1276
        be sure: for example with vfat mounted on unix, or a windows sftp
1215
1277
        server."""
1216
1278
        # TODO: Perhaps return a e.g. TransportCharacteristics that can answer
1223
1285
        # should be asked to ConnectedTransport only.
1224
1286
        return None
1225
1287
 
 
1288
    def _redirected_to(self, source, target):
 
1289
        """Returns a transport suitable to re-issue a redirected request.
 
1290
 
 
1291
        :param source: The source url as returned by the server.
 
1292
        :param target: The target url as returned by the server.
 
1293
 
 
1294
        The redirection can be handled only if the relpath involved is not
 
1295
        renamed by the redirection.
 
1296
 
 
1297
        :returns: A transport or None.
 
1298
        """
 
1299
        # This returns None by default, meaning the transport can't handle the
 
1300
        # redirection.
 
1301
        return None
 
1302
 
 
1303
 
1226
1304
 
1227
1305
class _SharedConnection(object):
1228
1306
    """A connection shared between several transports."""
1298
1376
 
1299
1377
    @staticmethod
1300
1378
    def _split_url(url):
1301
 
        """
1302
 
        Extract the server address, the credentials and the path from the url.
1303
 
 
1304
 
        user, password, host and path should be quoted if they contain reserved
1305
 
        chars.
1306
 
 
1307
 
        :param url: an quoted url
1308
 
 
1309
 
        :return: (scheme, user, password, host, port, path) tuple, all fields
1310
 
            are unquoted.
1311
 
        """
1312
 
        if isinstance(url, unicode):
1313
 
            raise errors.InvalidURL('should be ascii:\n%r' % url)
1314
 
        url = url.encode('utf-8')
1315
 
        (scheme, netloc, path, params,
1316
 
         query, fragment) = urlparse.urlparse(url, allow_fragments=False)
1317
 
        user = password = host = port = None
1318
 
        if '@' in netloc:
1319
 
            user, host = netloc.rsplit('@', 1)
1320
 
            if ':' in user:
1321
 
                user, password = user.split(':', 1)
1322
 
                password = urllib.unquote(password)
1323
 
            user = urllib.unquote(user)
1324
 
        else:
1325
 
            host = netloc
1326
 
 
1327
 
        if ':' in host:
1328
 
            host, port = host.rsplit(':', 1)
1329
 
            try:
1330
 
                port = int(port)
1331
 
            except ValueError:
1332
 
                raise errors.InvalidURL('invalid port number %s in url:\n%s' %
1333
 
                                        (port, url))
1334
 
        if host == '':
1335
 
            raise errors.InvalidURL('Host empty in: %s' % url)
1336
 
 
1337
 
        host = urllib.unquote(host)
1338
 
        path = urllib.unquote(path)
1339
 
 
1340
 
        return (scheme, user, password, host, port, path)
 
1379
        return urlutils.parse_url(url)
1341
1380
 
1342
1381
    @staticmethod
1343
1382
    def _unsplit_url(scheme, user, password, host, port, path):
1369
1408
            netloc = '%s@%s' % (urllib.quote(user), netloc)
1370
1409
        if port is not None:
1371
1410
            netloc = '%s:%d' % (netloc, port)
1372
 
        path = urllib.quote(path)
 
1411
        path = urlutils.escape(path)
1373
1412
        return urlparse.urlunparse((scheme, netloc, path, None, None, None))
1374
1413
 
1375
1414
    def relpath(self, abspath):
1394
1433
 
1395
1434
    def abspath(self, relpath):
1396
1435
        """Return the full url to the given relative path.
1397
 
        
 
1436
 
1398
1437
        :param relpath: the relative path urlencoded
1399
1438
 
1400
1439
        :returns: the Unicode version of the absolute path for relpath.
1460
1499
 
1461
1500
        Some protocols can renegociate the credentials within a connection,
1462
1501
        this method allows daughter classes to share updated credentials.
1463
 
        
 
1502
 
1464
1503
        :param credentials: the updated credentials.
1465
1504
        """
1466
1505
        # We don't want to call _set_connection here as we are only updating
1534
1573
    def convert_path_to_url(base, error_str):
1535
1574
        m = _urlRE.match(base)
1536
1575
        if m:
1537
 
            # This looks like a URL, but we weren't able to 
 
1576
            # This looks like a URL, but we weren't able to
1538
1577
            # instantiate it as such raise an appropriate error
1539
1578
            # FIXME: we have a 'error_str' unused and we use last_err below
1540
1579
            raise errors.UnsupportedProtocol(base, last_err)
1561
1600
                    possible_transports.append(t_same_connection)
1562
1601
                return t_same_connection
1563
1602
 
1564
 
    for proto, factory_list in transport_list_registry.iteritems():
 
1603
    for proto, factory_list in transport_list_registry.items():
1565
1604
        if proto is not None and base.startswith(proto):
1566
1605
            transport, last_err = _try_transport_factories(base, factory_list)
1567
1606
            if transport:
1606
1645
    :param action: A callable, what the caller want to do while catching
1607
1646
                  redirections.
1608
1647
    :param transport: The initial transport used.
1609
 
    :param redirected: A callable receiving the redirected transport and the 
 
1648
    :param redirected: A callable receiving the redirected transport and the
1610
1649
                  RedirectRequested exception.
1611
1650
 
1612
1651
    :return: Whatever 'action' returns
1639
1678
 
1640
1679
class Server(object):
1641
1680
    """A Transport Server.
1642
 
    
1643
 
    The Server interface provides a server for a given transport. We use
1644
 
    these servers as loopback testing tools. For any given transport the
1645
 
    Servers it provides must either allow writing, or serve the contents
1646
 
    of os.getcwdu() at the time setUp is called.
1647
 
    
1648
 
    Note that these are real servers - they must implement all the things
1649
 
    that we want bzr transports to take advantage of.
 
1681
 
 
1682
    The Server interface provides a server for a given transport type.
1650
1683
    """
1651
1684
 
1652
 
    def setUp(self):
 
1685
    def start_server(self):
1653
1686
        """Setup the server to service requests."""
1654
1687
 
1655
 
    def tearDown(self):
 
1688
    def stop_server(self):
1656
1689
        """Remove the server and cleanup any resources it owns."""
1657
1690
 
1658
 
    def get_url(self):
1659
 
        """Return a url for this server.
1660
 
        
1661
 
        If the transport does not represent a disk directory (i.e. it is 
1662
 
        a database like svn, or a memory only transport, it should return
1663
 
        a connection to a newly established resource for this Server.
1664
 
        Otherwise it should return a url that will provide access to the path
1665
 
        that was os.getcwdu() when setUp() was called.
1666
 
        
1667
 
        Subsequent calls will return the same resource.
1668
 
        """
1669
 
        raise NotImplementedError
1670
 
 
1671
 
    def get_bogus_url(self):
1672
 
        """Return a url for this protocol, that will fail to connect.
1673
 
        
1674
 
        This may raise NotImplementedError to indicate that this server cannot
1675
 
        provide bogus urls.
1676
 
        """
1677
 
        raise NotImplementedError
1678
 
 
1679
1691
 
1680
1692
# None is the default transport, for things with no url scheme
1681
1693
register_transport_proto('file://',
1713
1725
                 help="Read-only access of branches exported on the web.")
1714
1726
register_transport_proto('https://',
1715
1727
            help="Read-only access of branches exported on the web using SSL.")
 
1728
# The default http implementation is urllib, but https is pycurl if available
 
1729
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl',
 
1730
                        'PyCurlTransport')
1716
1731
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
1717
1732
                        'HttpTransport_urllib')
1718
1733
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
1719
1734
                        'HttpTransport_urllib')
1720
 
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl',
1721
 
                        'PyCurlTransport')
1722
1735
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl',
1723
1736
                        'PyCurlTransport')
1724
1737
 
1727
1740
register_transport_proto('aftp://', help="Access using active FTP.")
1728
1741
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport')
1729
1742
 
1730
 
# Default to trying GSSAPI authentication (if the kerberos module is available)
1731
 
register_transport_proto('ftp+gssapi://', register_netloc=True)
1732
 
register_lazy_transport('ftp+gssapi://', 'bzrlib.transport.ftp._gssapi', 
1733
 
                        'GSSAPIFtpTransport')
1734
 
register_transport_proto('aftp+gssapi://', register_netloc=True)
1735
 
register_lazy_transport('aftp+gssapi://', 'bzrlib.transport.ftp._gssapi', 
1736
 
                        'GSSAPIFtpTransport')
1737
 
register_transport_proto('ftp+nogssapi://', register_netloc=True)
1738
 
register_transport_proto('aftp+nogssapi://', register_netloc=True)
1739
 
 
1740
 
register_lazy_transport('ftp://', 'bzrlib.transport.ftp._gssapi', 
1741
 
                        'GSSAPIFtpTransport')
1742
 
register_lazy_transport('aftp://', 'bzrlib.transport.ftp._gssapi', 
1743
 
                        'GSSAPIFtpTransport')
1744
 
register_lazy_transport('ftp+nogssapi://', 'bzrlib.transport.ftp', 
1745
 
                        'FtpTransport')
1746
 
register_lazy_transport('aftp+nogssapi://', 'bzrlib.transport.ftp', 
1747
 
                        'FtpTransport')
 
1743
try:
 
1744
    import kerberos
 
1745
    kerberos_available = True
 
1746
except ImportError:
 
1747
    kerberos_available = False
 
1748
 
 
1749
if kerberos_available:
 
1750
    # Default to trying GSSAPI authentication (if the kerberos module is
 
1751
    # available)
 
1752
    register_transport_proto('ftp+gssapi://', register_netloc=True)
 
1753
    register_lazy_transport('ftp+gssapi://', 'bzrlib.transport.ftp._gssapi',
 
1754
                            'GSSAPIFtpTransport')
 
1755
    register_transport_proto('aftp+gssapi://', register_netloc=True)
 
1756
    register_lazy_transport('aftp+gssapi://', 'bzrlib.transport.ftp._gssapi',
 
1757
                            'GSSAPIFtpTransport')
 
1758
    register_transport_proto('ftp+nogssapi://', register_netloc=True)
 
1759
    register_transport_proto('aftp+nogssapi://', register_netloc=True)
 
1760
 
 
1761
    register_lazy_transport('ftp://', 'bzrlib.transport.ftp._gssapi',
 
1762
                            'GSSAPIFtpTransport')
 
1763
    register_lazy_transport('aftp://', 'bzrlib.transport.ftp._gssapi',
 
1764
                            'GSSAPIFtpTransport')
 
1765
    register_lazy_transport('ftp+nogssapi://', 'bzrlib.transport.ftp',
 
1766
                            'FtpTransport')
 
1767
    register_lazy_transport('aftp+nogssapi://', 'bzrlib.transport.ftp',
 
1768
                            'FtpTransport')
1748
1769
 
1749
1770
register_transport_proto('memory://')
1750
1771
register_lazy_transport('memory://', 'bzrlib.transport.memory',
1819
1840
            register_netloc=True)
1820
1841
register_lazy_transport('bzr+ssh://', 'bzrlib.transport.remote',
1821
1842
                        'RemoteSSHTransport')
 
1843
 
 
1844
register_transport_proto('ssh:')
 
1845
register_lazy_transport('ssh:', 'bzrlib.transport.remote',
 
1846
                        'HintingSSHTransport')
 
1847
 
 
1848
 
 
1849
transport_server_registry = registry.Registry()
 
1850
transport_server_registry.register_lazy('bzr', 'bzrlib.smart.server',
 
1851
    'serve_bzr', help="The Bazaar smart server protocol over TCP. (default port: 4155)")
 
1852
transport_server_registry.default_key = 'bzr'