/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
1
# Copyright (C) 2005, 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.11.19 by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.11.19 by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.11.19 by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings.
13
# You should have received a copy of the GNU General Public License
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
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
16
1185.11.19 by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings.
17
"""Transport is an abstraction layer to handle file access.
18
19
The abstraction is to allow access from the local filesystem, as well
20
as remote (such as http or sftp).
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
21
22
Transports are constructed from a string, being a URL or (as a degenerate
23
case) a local filesystem path.  This is typically the top directory of
24
a bzrdir, repository, or similar object we are interested in working with.
25
The Transport returned has methods to read, write and manipulate files within
26
it.
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
27
"""
28
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
29
import errno
1594.2.17 by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading.
30
from collections import deque
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
31
from copy import deepcopy
1955.3.1 by John Arbash Meinel
Add put_bytes() and a base-level implementation for it
32
from cStringIO import StringIO
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
33
import re
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
34
from stat import S_ISDIR
1530.1.7 by Robert Collins
merge integration.
35
import sys
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
36
from unittest import TestSuite
1685.1.70 by Wouter van Heyst
working on get_parent, set_parent and relative urls, broken
37
import urllib
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
38
import urlparse
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
39
import warnings
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
40
1725.2.3 by Robert Collins
Remove import of pumpfile from inner loop of commit.
41
import bzrlib
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
42
from bzrlib import (
43
    errors,
44
    osutils,
45
    symbol_versioning,
46
    urlutils,
47
    )
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
48
from bzrlib.errors import DependencyNotPresent
1725.2.3 by Robert Collins
Remove import of pumpfile from inner loop of commit.
49
from bzrlib.osutils import pumpfile
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
50
from bzrlib.symbol_versioning import (
51
        deprecated_passed,
52
        deprecated_method,
53
        deprecated_function,
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
54
        DEPRECATED_PARAMETER,
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
55
        zero_eight,
56
        zero_eleven,
57
        )
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
58
from bzrlib.trace import mutter, warning
907.1.45 by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary.
59
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
60
# {prefix: [transport_classes]}
61
# Transports are inserted onto the list LIFO and tried in order; as a result
62
# transports provided by plugins are tried first, which is usually what we
63
# want.
907.1.45 by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary.
64
_protocol_handlers = {
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
65
}
66
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
67
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER):
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
68
    """Register a transport that can be used to open URLs
69
70
    Normally you should use register_lazy_transport, which defers loading the
71
    implementation until it's actually used, and so avoids pulling in possibly
72
    large implementation libraries.
73
    """
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
74
    # Note that this code runs very early in library setup -- trace may not be
75
    # working, etc.
907.1.45 by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary.
76
    global _protocol_handlers
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
77
    if deprecated_passed(override):
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
78
        warnings.warn("register_transport(override) is deprecated")
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
79
    _protocol_handlers.setdefault(prefix, []).insert(0, klass)
80
81
82
def register_lazy_transport(scheme, module, classname):
83
    """Register lazy-loaded transport class.
84
85
    When opening a URL with the given scheme, load the module and then
86
    instantiate the particular class.  
87
88
    If the module raises DependencyNotPresent when it's imported, it is
89
    skipped and another implementation of the protocol is tried.  This is
90
    intended to be used when the implementation depends on an external
91
    implementation that may not be present.  If any other error is raised, it
92
    propagates up and the attempt to open the url fails.
93
    """
94
    # TODO: If no implementation of a protocol is available because of missing
95
    # dependencies, we should perhaps show the message about what dependency
96
    # was missing.
97
    def _loader(base):
98
        mod = __import__(module, globals(), locals(), [classname])
99
        klass = getattr(mod, classname)
100
        return klass(base)
101
    _loader.module = module
102
    register_transport(scheme, _loader)
907.1.45 by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary.
103
1442.1.24 by Robert Collins
Pull up _check_id and _relpath from Text and CompressedText stores into TransportStore
104
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
105
def _get_protocol_handlers():
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
106
    """Return a dictionary of {urlprefix: [factory]}"""
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
107
    return _protocol_handlers
108
109
110
def _set_protocol_handlers(new_handlers):
111
    """Replace the current protocol handlers dictionary.
112
113
    WARNING this will remove all build in protocols. Use with care.
114
    """
115
    global _protocol_handlers
116
    _protocol_handlers = new_handlers
117
118
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
119
def _clear_protocol_handlers():
120
    global _protocol_handlers
121
    _protocol_handlers = {}
122
123
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
124
def _get_transport_modules():
125
    """Return a list of the modules providing transports."""
126
    modules = set()
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
127
    for prefix, factory_list in _protocol_handlers.items():
128
        for factory in factory_list:
129
            if factory.__module__ == "bzrlib.transport":
130
                # this is a lazy load transport, because no real ones
131
                # are directlry in bzrlib.transport
132
                modules.add(factory.module)
133
            else:
134
                modules.add(factory.__module__)
1530.1.19 by Robert Collins
Make transport test adapter tests reliable.
135
    result = list(modules)
136
    result.sort()
137
    return result
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
138
139
1636.1.2 by Robert Collins
More review fixen to the relpath at '/' fixes.
140
def register_urlparse_netloc_protocol(protocol):
1636.1.1 by Robert Collins
Fix calling relpath() and abspath() on transports at their root.
141
    """Ensure that protocol is setup to be used with urlparse netloc parsing."""
142
    if protocol not in urlparse.uses_netloc:
143
        urlparse.uses_netloc.append(protocol)
144
145
1707.3.4 by John Arbash Meinel
Moved most of sftp.split_url into a Transport function.
146
def split_url(url):
1685.1.69 by Wouter van Heyst
merge bzr.dev 1740
147
    # TODO: jam 20060606 urls should only be ascii, or they should raise InvalidURL
1707.3.4 by John Arbash Meinel
Moved most of sftp.split_url into a Transport function.
148
    if isinstance(url, unicode):
149
        url = url.encode('utf-8')
150
    (scheme, netloc, path, params,
151
     query, fragment) = urlparse.urlparse(url, allow_fragments=False)
152
    username = password = host = port = None
153
    if '@' in netloc:
154
        username, host = netloc.split('@', 1)
155
        if ':' in username:
156
            username, password = username.split(':', 1)
157
            password = urllib.unquote(password)
158
        username = urllib.unquote(username)
159
    else:
160
        host = netloc
161
162
    if ':' in host:
163
        host, port = host.rsplit(':', 1)
164
        try:
165
            port = int(port)
166
        except ValueError:
167
            # TODO: Should this be ConnectionError?
1910.15.8 by Andrew Bennetts
Put url in 'invalid port number' message on a new line.
168
            raise errors.TransportError(
169
                'invalid port number %s in url:\n%s' % (port, url))
1707.3.4 by John Arbash Meinel
Moved most of sftp.split_url into a Transport function.
170
    host = urllib.unquote(host)
171
172
    path = urllib.unquote(path)
173
174
    return (scheme, username, password, host, port, path)
175
176
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
177
class _CoalescedOffset(object):
178
    """A data container for keeping track of coalesced offsets."""
179
180
    __slots__ = ['start', 'length', 'ranges']
181
182
    def __init__(self, start, length, ranges):
183
        self.start = start
184
        self.length = length
185
        self.ranges = ranges
186
187
    def __cmp__(self, other):
188
        return cmp((self.start, self.length, self.ranges),
189
                   (other.start, other.length, other.ranges))
190
191
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
192
class Transport(object):
193
    """This class encapsulates methods for retrieving or putting a file
194
    from/to a storage location.
195
196
    Most functions have a _multi variant, which allows you to queue up
197
    multiple requests. They generally have a dumb base implementation 
198
    which just iterates over the arguments, but smart Transport
199
    implementations can do pipelining.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
200
    In general implementations should support having a generator or a list
201
    as an argument (ie always iterate, never index)
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
202
203
    :ivar base: Base URL for the transport; should always end in a slash.
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
204
    """
205
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
206
    # implementations can override this if it is more efficient
207
    # for them to combine larger read chunks together
1864.5.4 by John Arbash Meinel
play around with tuning the partial reads.
208
    _max_readv_combine = 50
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
209
    # It is better to read this much more data in order, rather
210
    # than doing another seek. Even for the local filesystem,
211
    # there is a benefit in just reading.
212
    # TODO: jam 20060714 Do some real benchmarking to figure out
213
    #       where the biggest benefit between combining reads and
1864.5.8 by John Arbash Meinel
Cleanup and NEWS
214
    #       and seeking is. Consider a runtime auto-tune.
1864.5.4 by John Arbash Meinel
play around with tuning the partial reads.
215
    _bytes_to_read_before_seek = 0
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
216
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
217
    def __init__(self, base):
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
218
        super(Transport, self).__init__()
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
219
        self.base = base
220
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
221
    def _translate_error(self, e, path, raise_generic=True):
222
        """Translate an IOError or OSError into an appropriate bzr error.
223
224
        This handles things like ENOENT, ENOTDIR, EEXIST, and EACCESS
225
        """
1963.2.6 by Robey Pointer
pychecker is on crack; go back to using 'is None'.
226
        if getattr(e, 'errno', None) is not None:
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
227
            if e.errno in (errno.ENOENT, errno.ENOTDIR):
228
                raise errors.NoSuchFile(path, extra=e)
1185.31.58 by John Arbash Meinel
Updating for new transport tests so that they pass on win32
229
            # I would rather use errno.EFOO, but there doesn't seem to be
230
            # any matching for 267
231
            # This is the error when doing a listdir on a file:
232
            # WindowsError: [Errno 267] The directory name is invalid
233
            if sys.platform == 'win32' and e.errno in (errno.ESRCH, 267):
234
                raise errors.NoSuchFile(path, extra=e)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
235
            if e.errno == errno.EEXIST:
236
                raise errors.FileExists(path, extra=e)
237
            if e.errno == errno.EACCES:
238
                raise errors.PermissionDenied(path, extra=e)
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
239
            if e.errno == errno.ENOTEMPTY:
240
                raise errors.DirectoryNotEmpty(path, extra=e)
1558.10.1 by Aaron Bentley
Handle lockdirs over NFS properly
241
            if e.errno == errno.EBUSY:
242
                raise errors.ResourceBusy(path, extra=e)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
243
        if raise_generic:
244
            raise errors.TransportError(orig_error=e)
245
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
246
    def clone(self, offset=None):
247
        """Return a new Transport object, cloned from the current location,
1185.11.6 by John Arbash Meinel
Made HttpTransport handle a request for a parent directory differently.
248
        using a subdirectory or parent directory. This allows connections 
249
        to be pooled, rather than a new one needed for each subdir.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
250
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
251
        raise NotImplementedError(self.clone)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
252
907.1.32 by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate.
253
    def should_cache(self):
254
        """Return True if the data pulled across should be cached locally.
907.1.22 by John Arbash Meinel
Fixed some encoding issues, added is_remote function for Transport objects.
255
        """
907.1.32 by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate.
256
        return False
907.1.22 by John Arbash Meinel
Fixed some encoding issues, added is_remote function for Transport objects.
257
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
258
    def _pump(self, from_file, to_file):
259
        """Most children will need to copy from one file-like 
260
        object or string to another one.
261
        This just gives them something easy to call.
262
        """
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
263
        assert not isinstance(from_file, basestring), \
264
            '_pump should only be called on files not %s' % (type(from_file,))
265
        pumpfile(from_file, to_file)
1948.3.8 by Vincent LADEUIL
_pump accepts strings finally :)
266
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
267
    def _get_total(self, multi):
268
        """Try to figure out how many entries are in multi,
269
        but if not possible, return None.
270
        """
271
        try:
272
            return len(multi)
273
        except TypeError: # We can't tell how many, because relpaths is a generator
274
            return None
275
276
    def _update_pb(self, pb, msg, count, total):
277
        """Update the progress bar based on the current count
278
        and total available, total may be None if it was
279
        not possible to determine.
280
        """
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
281
        if pb is None:
282
            return
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
283
        if total is None:
284
            pb.update(msg, count, count+1)
285
        else:
286
            pb.update(msg, count, total)
287
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
288
    def _iterate_over(self, multi, func, pb, msg, expand=True):
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
289
        """Iterate over all entries in multi, passing them to func,
290
        and update the progress bar as you go along.
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
291
292
        :param expand:  If True, the entries will be passed to the function
293
                        by expanding the tuple. If False, it will be passed
294
                        as a single parameter.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
295
        """
296
        total = self._get_total(multi)
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
297
        result = []
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
298
        count = 0
299
        for entry in multi:
300
            self._update_pb(pb, msg, count, total)
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
301
            if expand:
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
302
                result.append(func(*entry))
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
303
            else:
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
304
                result.append(func(entry))
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
305
            count += 1
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
306
        return tuple(result)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
307
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
308
    def abspath(self, relpath):
309
        """Return the full url to the given relative path.
1910.16.6 by Andrew Bennetts
Update Transport.abspath docstring.
310
311
        :param relpath: a string of a relative path
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
312
        """
1442.1.44 by Robert Collins
Many transport related tweaks:
313
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
314
        # XXX: Robert Collins 20051016 - is this really needed in the public
315
        # interface ?
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
316
        raise NotImplementedError(self.abspath)
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
317
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
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)
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
344
        if relpath.startswith('/'):
345
            base_parts = []
346
        else:
347
            base_parts = base_path.split('/')
1910.16.2 by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport.
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
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
364
    def relpath(self, abspath):
365
        """Return the local path portion from a given absolute path.
1442.1.44 by Robert Collins
Many transport related tweaks:
366
367
        This default implementation is not suitable for filesystems with
368
        aliasing, such as that given by symlinks, where a path may not 
369
        start with our base, but still be a relpath once aliasing is 
370
        resolved.
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
371
        """
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
372
        # TODO: This might want to use bzrlib.osutils.relpath
373
        #       but we have to watch out because of the prefix issues
1530.1.3 by Robert Collins
transport implementations now tested consistently.
374
        if not (abspath == self.base[:-1] or abspath.startswith(self.base)):
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
375
            raise errors.PathNotChild(abspath, self.base)
1442.1.44 by Robert Collins
Many transport related tweaks:
376
        pl = len(self.base)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
377
        return abspath[pl:].strip('/')
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
378
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
379
    def local_abspath(self, relpath):
380
        """Return the absolute path on the local filesystem.
381
382
        This function will only be defined for Transports which have a
383
        physical local filesystem representation.
384
        """
1685.1.11 by John Arbash Meinel
Not all of the registered transports use :// as part of their path, specifically memory:/
385
        # TODO: jam 20060426 Should this raise NotLocalUrl instead?
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
386
        raise errors.TransportNotPossible('This is not a LocalTransport,'
387
            ' so there is no local representation for a path')
388
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
389
    def has(self, relpath):
1442.1.44 by Robert Collins
Many transport related tweaks:
390
        """Does the file relpath exist?
391
        
392
        Note that some transports MAY allow querying on directories, but this
1553.5.66 by Martin Pool
doc
393
        is not part of the protocol.  In other words, the results of 
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
394
        t.has("a_directory_name") are undefined.
1910.7.17 by Andrew Bennetts
Various cosmetic changes.
395
396
        :rtype: bool
1442.1.44 by Robert Collins
Many transport related tweaks:
397
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
398
        raise NotImplementedError(self.has)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
399
907.1.36 by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class.
400
    def has_multi(self, relpaths, pb=None):
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
401
        """Return True/False for each entry in relpaths"""
402
        total = self._get_total(relpaths)
403
        count = 0
404
        for relpath in relpaths:
907.1.36 by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class.
405
            self._update_pb(pb, 'has', count, total)
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
406
            yield self.has(relpath)
407
            count += 1
408
1185.16.155 by John Arbash Meinel
Added a has_any function to the Transport API
409
    def has_any(self, relpaths):
410
        """Return True if any of the paths exist."""
411
        for relpath in relpaths:
412
            if self.has(relpath):
413
                return True
414
        return False
415
1442.1.44 by Robert Collins
Many transport related tweaks:
416
    def iter_files_recursive(self):
417
        """Iter the relative paths of files in the transports sub-tree.
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
418
419
        *NOTE*: This only lists *files*, not subdirectories!
1442.1.44 by Robert Collins
Many transport related tweaks:
420
        
421
        As with other listing functions, only some transports implement this,.
422
        you may check via is_listable to determine if it will.
423
        """
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
424
        raise errors.TransportNotPossible("This transport has not "
1530.1.21 by Robert Collins
Review feedback fixes.
425
                                          "implemented iter_files_recursive "
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
426
                                          "(but must claim to be listable "
427
                                          "to trigger this error).")
1442.1.44 by Robert Collins
Many transport related tweaks:
428
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
429
    def get(self, relpath):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
430
        """Get the file at the given relative path.
907.1.20 by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8
431
432
        :param relpath: The relative path to the file
1910.19.2 by Andrew Bennetts
Add a new method ``Transport.get_smart_client()``. This is provided to allow
433
        :rtype: File-like object.
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
434
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
435
        raise NotImplementedError(self.get)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
436
1955.3.3 by John Arbash Meinel
Implement and test 'get_bytes'
437
    def get_bytes(self, relpath):
438
        """Get a raw string of the bytes for a file at the given location.
439
440
        :param relpath: The relative path to the file
441
        """
442
        return self.get(relpath).read()
443
1910.19.2 by Andrew Bennetts
Add a new method ``Transport.get_smart_client()``. This is provided to allow
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
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
451
    def readv(self, relpath, offsets):
452
        """Get parts of the file at the given relative path.
453
454
        :offsets: A list of (offset, size) tuples.
455
        :return: A list or generator of (offset, data) tuples
456
        """
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
457
        if not offsets:
1594.2.16 by Robert Collins
Coalesce readv requests on file based transports.
458
            return
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
459
1864.5.7 by John Arbash Meinel
remove disable prefetch support
460
        fp = self.get(relpath)
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
461
        return self._seek_and_read(fp, offsets, relpath)
1864.5.11 by John Arbash Meinel
Factor out the workhorse of Transport.readv() into a helper function, and re-use that function in sftp but with a non-prefetch file.
462
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
463
    def _seek_and_read(self, fp, offsets, relpath='<unknown>'):
1864.5.11 by John Arbash Meinel
Factor out the workhorse of Transport.readv() into a helper function, and re-use that function in sftp but with a non-prefetch file.
464
        """An implementation of readv that uses fp.seek and fp.read.
465
466
        This uses _coalesce_offsets to issue larger reads and fewer seeks.
467
468
        :param fp: A file-like object that supports seek() and read(size)
469
        :param offsets: A list of offsets to be read from the given file.
470
        :return: yield (pos, data) tuples for each request
471
        """
1864.5.2 by John Arbash Meinel
always read in sorted order, and return in requested order, but only cache what is currently out of order
472
        # We are going to iterate multiple times, we need a list
473
        offsets = list(offsets)
474
        sorted_offsets = sorted(offsets)
475
476
        # turn the list of offsets into a stack
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
477
        offset_stack = iter(offsets)
478
        cur_offset_and_size = offset_stack.next()
1864.5.2 by John Arbash Meinel
always read in sorted order, and return in requested order, but only cache what is currently out of order
479
        coalesced = self._coalesce_offsets(sorted_offsets,
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
480
                               limit=self._max_readv_combine,
481
                               fudge_factor=self._bytes_to_read_before_seek)
1864.5.2 by John Arbash Meinel
always read in sorted order, and return in requested order, but only cache what is currently out of order
482
483
        # Cache the results, but only until they have been fulfilled
484
        data_map = {}
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
485
        for c_offset in coalesced:
1864.5.11 by John Arbash Meinel
Factor out the workhorse of Transport.readv() into a helper function, and re-use that function in sftp but with a non-prefetch file.
486
            # TODO: jam 20060724 it might be faster to not issue seek if 
487
            #       we are already at the right location. This should be
488
            #       benchmarked.
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
489
            fp.seek(c_offset.start)
490
            data = fp.read(c_offset.length)
2001.3.2 by John Arbash Meinel
Force all transports to raise ShortReadvError if they can
491
            if len(data) < c_offset.length:
492
                raise errors.ShortReadvError(relpath, c_offset.start,
2001.3.3 by John Arbash Meinel
review feedback: add the actual count written to ShortReadvError
493
                            c_offset.length, actual=len(data))
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
494
            for suboffset, subsize in c_offset.ranges:
495
                key = (c_offset.start+suboffset, subsize)
496
                data_map[key] = data[suboffset:suboffset+subsize]
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
497
1864.5.8 by John Arbash Meinel
Cleanup and NEWS
498
            # Now that we've read some data, see if we can yield anything back
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
499
            while cur_offset_and_size in data_map:
500
                this_data = data_map.pop(cur_offset_and_size)
501
                yield cur_offset_and_size[0], this_data
502
                cur_offset_and_size = offset_stack.next()
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
503
504
    @staticmethod
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
505
    def _coalesce_offsets(offsets, limit, fudge_factor):
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
506
        """Yield coalesced offsets.
507
508
        With a long list of neighboring requests, combine them
509
        into a single large request, while retaining the original
510
        offsets.
511
        Turns  [(15, 10), (25, 10)] => [(15, 20, [(0, 10), (10, 10)])]
512
513
        :param offsets: A list of (start, length) pairs
514
        :param limit: Only combine a maximum of this many pairs
515
                      Some transports penalize multiple reads more than
516
                      others, and sometimes it is better to return early.
517
                      0 means no limit
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
518
        :param fudge_factor: All transports have some level of 'it is
519
                better to read some more data and throw it away rather 
520
                than seek', so collapse if we are 'close enough'
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
521
        :return: yield _CoalescedOffset objects, which have members for wher
522
                to start, how much to read, and how to split those 
523
                chunks back up
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
524
        """
525
        last_end = None
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
526
        cur = _CoalescedOffset(None, None, [])
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
527
528
        for start, size in offsets:
529
            end = start + size
530
            if (last_end is not None 
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
531
                and start <= last_end + fudge_factor
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
532
                and start >= cur.start
533
                and (limit <= 0 or len(cur.ranges) < limit)):
534
                cur.length = end - cur.start
535
                cur.ranges.append((start-cur.start, size))
1594.2.16 by Robert Collins
Coalesce readv requests on file based transports.
536
            else:
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
537
                if cur.start is not None:
538
                    yield cur
539
                cur = _CoalescedOffset(start, size, [(0, size)])
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
540
            last_end = end
541
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
542
        if cur.start is not None:
543
            yield cur
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
544
545
        return
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
546
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
547
    def get_multi(self, relpaths, pb=None):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
548
        """Get a list of file-like objects, one for each entry in relpaths.
549
550
        :param relpaths: A list of relative paths.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
551
        :param pb:  An optional ProgressBar for indicating percent done.
552
        :return: A list or generator of file-like objects
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
553
        """
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
554
        # TODO: Consider having this actually buffer the requests,
555
        # in the default mode, it probably won't give worse performance,
556
        # and all children wouldn't have to implement buffering
907.1.16 by John Arbash Meinel
Fixing a few cut&paste typos.
557
        total = self._get_total(relpaths)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
558
        count = 0
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
559
        for relpath in relpaths:
907.1.16 by John Arbash Meinel
Fixing a few cut&paste typos.
560
            self._update_pb(pb, 'get', count, total)
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
561
            yield self.get(relpath)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
562
            count += 1
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
563
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
564
    @deprecated_method(zero_eleven)
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
565
    def put(self, relpath, f, mode=None):
1946.1.1 by John Arbash Meinel
Stub out the test and basic implementation for 'non_atomic_put'
566
        """Copy the file-like object into the location.
907.1.20 by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8
567
568
        :param relpath: Location to put the contents, relative to base.
1946.1.1 by John Arbash Meinel
Stub out the test and basic implementation for 'non_atomic_put'
569
        :param f:       File-like object.
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
570
        :param mode: The mode for the newly created file, 
571
                     None means just use the default
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
572
        """
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
573
        if isinstance(f, str):
574
            return self.put_bytes(relpath, f, mode=mode)
575
        else:
576
            return self.put_file(relpath, f, mode=mode)
577
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
578
    def put_bytes(self, relpath, bytes, mode=None):
579
        """Atomically put the supplied bytes into the given location.
580
581
        :param relpath: The location to put the contents, relative to the
582
            transport base.
583
        :param bytes: A bytestring of data.
584
        :param mode: Create the file with the given mode.
585
        :return: None
586
        """
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)
590
591
    def put_bytes_non_atomic(self, relpath, bytes, mode=None,
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
592
                             create_parent_dir=False,
593
                             dir_mode=None):
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
594
        """Copy the string into the target location.
595
596
        This function is not strictly safe to use. See 
597
        Transport.put_bytes_non_atomic for more information.
598
599
        :param relpath: The remote location to put the contents.
600
        :param bytes:   A string object containing the raw bytes to write into
601
                        the target file.
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.
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
607
        :param dir_mode: Possible access permissions for new directories.
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
608
        """
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,
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
612
                                 create_parent_dir=create_parent_dir,
613
                                 dir_mode=dir_mode)
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
614
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
615
    def put_file(self, relpath, f, mode=None):
616
        """Copy the file-like object into the location.
617
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.
622
        """
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'
627
                               ' version 0.11.'
628
                               % (self.__class__.__name__,),
629
                               DeprecationWarning)
630
        return self.put(relpath, f, mode=mode)
631
        #raise NotImplementedError(self.put_file)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
632
1955.3.27 by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions
633
    def put_file_non_atomic(self, relpath, f, mode=None,
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
634
                            create_parent_dir=False,
635
                            dir_mode=None):
1946.1.1 by John Arbash Meinel
Stub out the test and basic implementation for 'non_atomic_put'
636
        """Copy the file-like object into the target location.
637
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.
642
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.
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
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.
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
650
        :param dir_mode: Possible access permissions for new directories.
1946.1.1 by John Arbash Meinel
Stub out the test and basic implementation for 'non_atomic_put'
651
        """
652
        # Default implementation just does an atomic put.
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
653
        try:
1955.3.19 by John Arbash Meinel
rename non_atomic_put => non_atomic_put_file
654
            return self.put_file(relpath, f, mode=mode)
1946.1.8 by John Arbash Meinel
Update non_atomic_put to have a create_parent_dir flag
655
        except errors.NoSuchFile:
656
            if not create_parent_dir:
657
                raise
658
            parent_dir = osutils.dirname(relpath)
659
            if parent_dir:
1946.2.12 by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put
660
                self.mkdir(parent_dir, mode=dir_mode)
1955.3.19 by John Arbash Meinel
rename non_atomic_put => non_atomic_put_file
661
                return self.put_file(relpath, f, mode=mode)
1946.1.1 by John Arbash Meinel
Stub out the test and basic implementation for 'non_atomic_put'
662
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
663
    @deprecated_method(zero_eleven)
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
664
    def put_multi(self, files, mode=None, pb=None):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
665
        """Put a set of files into the location.
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
666
667
        :param files: A list of tuples of relpath, file object [(path1, file1), (path2, file2),...]
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
668
        :param pb:  An optional ProgressBar for indicating percent done.
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
669
        :param mode: The mode for the newly created files
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
670
        :return: The number of files copied.
671
        """
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
672
        def _put(path, f):
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
673
            if isinstance(f, str):
674
                self.put_bytes(path, f, mode=mode)
675
            else:
676
                self.put_file(path, f, mode=mode)
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
677
        return len(self._iterate_over(files, _put, pb, 'put', expand=True))
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
678
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
679
    def mkdir(self, relpath, mode=None):
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
680
        """Create a directory at the given path."""
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
681
        raise NotImplementedError(self.mkdir)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
682
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
683
    def mkdir_multi(self, relpaths, mode=None, pb=None):
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
684
        """Create a group of directories"""
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
685
        def mkdir(path):
686
            self.mkdir(path, mode=mode)
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
687
        return len(self._iterate_over(relpaths, mkdir, pb, 'mkdir', expand=False))
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
688
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
689
    @deprecated_method(zero_eleven)
1755.3.1 by Robert Collins
Tune the time to build our kernel_like tree : make LocalTransport.put faster, AtomicFile faster, LocalTransport.append faster.
690
    def append(self, relpath, f, mode=None):
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
691
        """Append the text in the file-like object to the supplied location.
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
692
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
693
        returns the length of relpath before the content was written to it.
1755.3.1 by Robert Collins
Tune the time to build our kernel_like tree : make LocalTransport.put faster, AtomicFile faster, LocalTransport.append faster.
694
        
695
        If the file does not exist, it is created with the supplied mode.
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
696
        """
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
697
        return self.append_file(relpath, f, mode=mode)
698
699
    def append_file(self, relpath, f, mode=None):
1910.7.18 by Andrew Bennetts
Merge from bzr.dev
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.
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
709
        """
710
        symbol_versioning.warn('Transport %s should implement append_file,'
711
                               ' rather than implementing append() as of'
712
                               ' version 0.11.'
713
                               % (self.__class__.__name__,),
714
                               DeprecationWarning)
715
        return self.append(relpath, f, mode=mode)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
716
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
717
    def append_bytes(self, relpath, bytes, mode=None):
1910.7.18 by Andrew Bennetts
Merge from bzr.dev
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.
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
728
        """
729
        assert isinstance(bytes, str), \
730
            'bytes must be a plain string, not %s' % type(bytes)
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
731
        return self.append_file(relpath, StringIO(bytes), mode=mode)
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
732
1185.11.19 by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings.
733
    def append_multi(self, files, pb=None):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
734
        """Append the text in each file-like or string object to
735
        the supplied location.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
736
737
        :param files: A set of (path, f) entries
738
        :param pb:  An optional ProgressBar for indicating percent done.
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
739
        """
1955.3.15 by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes
740
        return self._iterate_over(files, self.append_file, pb, 'append', expand=True)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
741
742
    def copy(self, rel_from, rel_to):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
743
        """Copy the item at rel_from to the location at rel_to.
744
        
745
        Override this for efficiency if a specific transport can do it 
746
        faster than this default implementation.
747
        """
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
748
        self.put_file(rel_to, self.get(rel_from))
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
749
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
750
    def copy_multi(self, relpaths, pb=None):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
751
        """Copy a bunch of entries.
752
        
753
        :param relpaths: A list of tuples of the form [(from, to), (from, to),...]
754
        """
755
        # This is the non-pipelined implementation, so that
756
        # implementors don't have to implement everything.
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
757
        return self._iterate_over(relpaths, self.copy, pb, 'copy', expand=True)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
758
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
759
    def copy_to(self, relpaths, other, mode=None, pb=None):
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
760
        """Copy a set of entries from self into another Transport.
761
762
        :param relpaths: A list/generator of entries to be copied.
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
763
        :param mode: This is the target mode for the newly created files
1185.16.156 by John Arbash Meinel
Adding a note about changing copy_to's interface
764
        TODO: This interface needs to be updated so that the target location
765
              can be different from the source location.
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
766
        """
767
        # The dummy implementation just does a simple get + put
768
        def copy_entry(path):
1955.3.11 by John Arbash Meinel
Clean up the rest of the api calls to deprecated functions in the test suite, and make sure Transport._pump is only accepting files, not strings
769
            other.put_file(path, self.get(path), mode=mode)
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
770
1563.2.3 by Robert Collins
Change the return signature of transport.append and append_multi to return the length of the pre-append content.
771
        return len(self._iterate_over(relpaths, copy_entry, pb, 'copy_to', expand=False))
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
772
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
773
    def copy_tree(self, from_relpath, to_relpath):
774
        """Copy a subtree from one relpath to another.
775
776
        If a faster implementation is available, specific transports should 
777
        implement it.
778
        """
779
        source = self.clone(from_relpath)
780
        self.mkdir(to_relpath)
781
        target = self.clone(to_relpath)
782
        files = []
783
        directories = ['.']
784
        while directories:
785
            dir = directories.pop()
786
            if dir != '.':
787
                target.mkdir(dir)
788
            for path in source.list_dir(dir):
789
                path = dir + '/' + path
790
                stat = source.stat(path)
791
                if S_ISDIR(stat.st_mode):
792
                    directories.append(path)
793
                else:
794
                    files.append(path)
795
        source.copy_to(files, target)
796
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
797
    def rename(self, rel_from, rel_to):
798
        """Rename a file or directory.
799
800
        This *must* fail if the destination is a nonempty directory - it must
801
        not automatically remove it.  It should raise DirectoryNotEmpty, or
802
        some other PathError if the case can't be specifically detected.
803
804
        If the destination is an empty directory or a file this function may
805
        either fail or succeed, depending on the underlying transport.  It
806
        should not attempt to remove the destination if overwriting is not the
807
        native transport behaviour.  If at all possible the transport should
808
        ensure that the rename either completes or not, without leaving the
809
        destination deleted and the new file not moved in place.
810
811
        This is intended mainly for use in implementing LockDir.
812
        """
813
        # transports may need to override this
1553.5.17 by Martin Pool
Transport.rename should be unimplemented in base class
814
        raise NotImplementedError(self.rename)
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
815
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
816
    def move(self, rel_from, rel_to):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
817
        """Move the item at rel_from to the location at rel_to.
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
818
819
        The destination is deleted if possible, even if it's a non-empty
820
        directory tree.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
821
        
822
        If a transport can directly implement this it is suggested that
823
        it do so for efficiency.
824
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
825
        if S_ISDIR(self.stat(rel_from).st_mode):
826
            self.copy_tree(rel_from, rel_to)
827
            self.delete_tree(rel_from)
828
        else:
829
            self.copy(rel_from, rel_to)
830
            self.delete(rel_from)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
831
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
832
    def move_multi(self, relpaths, pb=None):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
833
        """Move a bunch of entries.
834
        
835
        :param relpaths: A list of tuples of the form [(from1, to1), (from2, to2),...]
836
        """
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
837
        return self._iterate_over(relpaths, self.move, pb, 'move', expand=True)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
838
839
    def move_multi_to(self, relpaths, rel_to):
840
        """Move a bunch of entries to a single location.
841
        This differs from move_multi in that you give a list of from, and
842
        a single destination, rather than multiple destinations.
843
844
        :param relpaths: A list of relative paths [from1, from2, from3, ...]
845
        :param rel_to: A directory where each entry should be placed.
846
        """
847
        # This is not implemented, because you need to do special tricks to
848
        # extract the basename, and add it to rel_to
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
849
        raise NotImplementedError(self.move_multi_to)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
850
851
    def delete(self, relpath):
852
        """Delete the item at relpath"""
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
853
        raise NotImplementedError(self.delete)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
854
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
855
    def delete_multi(self, relpaths, pb=None):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
856
        """Queue up a bunch of deletes to be done.
857
        """
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
858
        return self._iterate_over(relpaths, self.delete, pb, 'delete', expand=False)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
859
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
860
    def delete_tree(self, relpath):
861
        """Delete an entire tree. This may require a listable transport."""
862
        subtree = self.clone(relpath)
863
        files = []
864
        directories = ['.']
865
        pending_rmdirs = []
866
        while directories:
867
            dir = directories.pop()
868
            if dir != '.':
869
                pending_rmdirs.append(dir)
870
            for path in subtree.list_dir(dir):
871
                path = dir + '/' + path
872
                stat = subtree.stat(path)
873
                if S_ISDIR(stat.st_mode):
874
                    directories.append(path)
875
                else:
876
                    files.append(path)
877
        subtree.delete_multi(files)
878
        pending_rmdirs.reverse()
879
        for dir in pending_rmdirs:
880
            subtree.rmdir(dir)
881
        self.rmdir(relpath)
882
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
883
    def __repr__(self):
884
        return "<%s.%s url=%s>" % (self.__module__, self.__class__.__name__, self.base)
885
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
886
    def stat(self, relpath):
887
        """Return the stat information for a file.
888
        WARNING: This may not be implementable for all protocols, so use
889
        sparingly.
1442.1.44 by Robert Collins
Many transport related tweaks:
890
        NOTE: This returns an object with fields such as 'st_size'. It MAY
891
        or MAY NOT return the literal result of an os.stat() call, so all
892
        access should be via named fields.
893
        ALSO NOTE: Stats of directories may not be supported on some 
894
        transports.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
895
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
896
        raise NotImplementedError(self.stat)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
897
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
898
    def rmdir(self, relpath):
899
        """Remove a directory at the given path."""
900
        raise NotImplementedError
901
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
902
    def stat_multi(self, relpaths, pb=None):
903
        """Stat multiple files and return the information.
904
        """
905
        #TODO:  Is it worth making this a generator instead of a
906
        #       returning a list?
907
        stats = []
908
        def gather(path):
909
            stats.append(self.stat(path))
910
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
911
        count = self._iterate_over(relpaths, gather, pb, 'stat', expand=False)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
912
        return stats
913
1400.1.1 by Robert Collins
implement a basic test for the ui branch command from http servers
914
    def listable(self):
915
        """Return True if this store supports listing."""
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
916
        raise NotImplementedError(self.listable)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
917
918
    def list_dir(self, relpath):
919
        """Return a list of all files at the given location.
920
        WARNING: many transports do not support this, so trying avoid using
921
        it if at all possible.
922
        """
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
923
        raise errors.TransportNotPossible("Transport %r has not "
1530.1.21 by Robert Collins
Review feedback fixes.
924
                                          "implemented list_dir "
1530.1.3 by Robert Collins
transport implementations now tested consistently.
925
                                          "(but must claim to be listable "
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
926
                                          "to trigger this error)."
927
                                          % (self))
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
928
907.1.24 by John Arbash Meinel
Remote functionality work.
929
    def lock_read(self, relpath):
930
        """Lock the given file for shared (read) access.
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
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.  
907.1.24 by John Arbash Meinel
Remote functionality work.
937
938
        :return: A lock object, which should contain an unlock() function.
939
        """
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
940
        raise errors.TransportNotPossible("transport locks not supported on %s" % self)
907.1.24 by John Arbash Meinel
Remote functionality work.
941
942
    def lock_write(self, relpath):
943
        """Lock the given file for exclusive (write) access.
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
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.
907.1.24 by John Arbash Meinel
Remote functionality work.
950
951
        :return: A lock object, which should contain an unlock() function.
952
        """
1910.16.1 by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible.
953
        raise errors.TransportNotPossible("transport locks not supported on %s" % self)
907.1.24 by John Arbash Meinel
Remote functionality work.
954
1530.1.3 by Robert Collins
transport implementations now tested consistently.
955
    def is_readonly(self):
956
        """Return true if this connection cannot be written to."""
957
        return False
958
1608.2.7 by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity
959
    def _can_roundtrip_unix_modebits(self):
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
960
        """Return true if this transport can store and retrieve unix modebits.
961
962
        (For example, 0700 to make a directory owner-private.)
963
        
964
        Note: most callers will not want to switch on this, but should rather 
965
        just try and set permissions and let them be either stored or not.
966
        This is intended mainly for the use of the test suite.
967
        
968
        Warning: this is not guaranteed to be accurate as sometimes we can't 
969
        be sure: for example with vfat mounted on unix, or a windows sftp
970
        server."""
971
        # TODO: Perhaps return a e.g. TransportCharacteristics that can answer
972
        # several questions about the transport.
973
        return False
974
907.1.24 by John Arbash Meinel
Remote functionality work.
975
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
976
# jam 20060426 For compatibility we copy the functions here
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
977
# TODO: The should be marked as deprecated
978
urlescape = urlutils.escape
979
urlunescape = urlutils.unescape
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
980
_urlRE = re.compile(r'^(?P<proto>[^:/\\]+)://(?P<path>.*)$')
981
982
1393.2.4 by John Arbash Meinel
All tests pass.
983
def get_transport(base):
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
984
    """Open a transport to access a URL or directory.
985
986
    base is either a URL or a directory name.  
987
    """
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
988
    # TODO: give a better error if base looks like a url but there's no
989
    # handler for the scheme?
907.1.45 by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary.
990
    global _protocol_handlers
907.1.13 by John Arbash Meinel
Fixed bzr root.
991
    if base is None:
1685.1.11 by John Arbash Meinel
Not all of the registered transports use :// as part of their path, specifically memory:/
992
        base = '.'
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
993
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
994
    last_err = None
995
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
996
    def convert_path_to_url(base, error_str):
997
        m = _urlRE.match(base)
998
        if m:
999
            # This looks like a URL, but we weren't able to 
1000
            # instantiate it as such raise an appropriate error
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
1001
            raise errors.UnsupportedProtocol(base, last_err)
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
1002
        # This doesn't look like a protocol, consider it a local path
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
1003
        new_base = urlutils.local_path_to_url(base)
1908.3.1 by Carl Friedrich Bolz
Clean up some mutter() calls.
1004
        # mutter('converting os path %r => url %s', base, new_base)
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
1005
        return new_base
1006
1007
    # Catch any URLs which are passing Unicode rather than ASCII
1008
    try:
1009
        base = base.encode('ascii')
1010
    except UnicodeError:
1011
        # Only local paths can be Unicode
1012
        base = convert_path_to_url(base,
1013
            'URLs must be properly escaped (protocol: %s)')
1685.1.11 by John Arbash Meinel
Not all of the registered transports use :// as part of their path, specifically memory:/
1014
    
1015
    for proto, factory_list in _protocol_handlers.iteritems():
1016
        if proto is not None and base.startswith(proto):
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
1017
            t, last_err = _try_transport_factories(base, factory_list)
1685.1.11 by John Arbash Meinel
Not all of the registered transports use :// as part of their path, specifically memory:/
1018
            if t:
1019
                return t
1685.1.9 by John Arbash Meinel
Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url
1020
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
1021
    # We tried all the different protocols, now try one last time
1022
    # as a local protocol
1023
    base = convert_path_to_url(base, 'Unsupported protocol: %s')
1685.1.11 by John Arbash Meinel
Not all of the registered transports use :// as part of their path, specifically memory:/
1024
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
1025
    # The default handler is the filesystem handler, stored as protocol None
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
1026
    return _try_transport_factories(base, _protocol_handlers[None])[0]
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
1027
1028
1029
def _try_transport_factories(base, factory_list):
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
1030
    last_err = None
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
1031
    for factory in factory_list:
1032
        try:
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
1033
            return factory(base), None
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
1034
        except DependencyNotPresent, e:
1035
            mutter("failed to instantiate transport %r for %r: %r" %
1036
                    (factory, base, e))
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
1037
            last_err = e
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
1038
            continue
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
1039
    return None, last_err
1185.16.81 by mbp at sourcefrog
[merge] robert
1040
1185.16.78 by Martin Pool
- load paramiko sftp transport by default
1041
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1042
class Server(object):
1530.1.21 by Robert Collins
Review feedback fixes.
1043
    """A Transport Server.
1044
    
1045
    The Server interface provides a server for a given transport. We use
1046
    these servers as loopback testing tools. For any given transport the
1047
    Servers it provides must either allow writing, or serve the contents
1048
    of os.getcwdu() at the time setUp is called.
1049
    
1050
    Note that these are real servers - they must implement all the things
1051
    that we want bzr transports to take advantage of.
1052
    """
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1053
1054
    def setUp(self):
1055
        """Setup the server to service requests."""
1056
1057
    def tearDown(self):
1058
        """Remove the server and cleanup any resources it owns."""
1059
1060
    def get_url(self):
1530.1.21 by Robert Collins
Review feedback fixes.
1061
        """Return a url for this server.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1062
        
1063
        If the transport does not represent a disk directory (i.e. it is 
1530.1.21 by Robert Collins
Review feedback fixes.
1064
        a database like svn, or a memory only transport, it should return
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1065
        a connection to a newly established resource for this Server.
1530.1.21 by Robert Collins
Review feedback fixes.
1066
        Otherwise it should return a url that will provide access to the path
1067
        that was os.getcwdu() when setUp() was called.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1068
        
1069
        Subsequent calls will return the same resource.
1070
        """
1071
        raise NotImplementedError
1072
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
1073
    def get_bogus_url(self):
1074
        """Return a url for this protocol, that will fail to connect."""
1075
        raise NotImplementedError
1076
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1077
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
1078
class TransportTestProviderAdapter(object):
1530.1.21 by Robert Collins
Review feedback fixes.
1079
    """A tool to generate a suite testing all transports for a single test.
1080
1081
    This is done by copying the test once for each transport and injecting
1082
    the transport_class and transport_server classes into each copy. Each copy
1083
    is also given a new id() to make it easy to identify.
1084
    """
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
1085
1086
    def adapt(self, test):
1087
        result = TestSuite()
1088
        for klass, server_factory in self._test_permutations():
1089
            new_test = deepcopy(test)
1090
            new_test.transport_class = klass
1091
            new_test.transport_server = server_factory
1530.1.3 by Robert Collins
transport implementations now tested consistently.
1092
            def make_new_test_id():
1093
                new_id = "%s(%s)" % (new_test.id(), server_factory.__name__)
1094
                return lambda: new_id
1095
            new_test.id = make_new_test_id()
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
1096
            result.addTest(new_test)
1097
        return result
1098
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
1099
    def get_transport_test_permutations(self, module):
1100
        """Get the permutations module wants to have tested."""
1963.2.6 by Robey Pointer
pychecker is on crack; go back to using 'is None'.
1101
        if getattr(module, 'get_test_permutations', None) is None:
1540.3.6 by Martin Pool
[merge] update from bzr.dev
1102
            warning("transport module %s doesn't provide get_test_permutations()"
1103
                    % module.__name__)
1104
            return []
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
1105
        return module.get_test_permutations()
1106
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
1107
    def _test_permutations(self):
1108
        """Return a list of the klass, server_factory pairs to test."""
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
1109
        result = []
1110
        for module in _get_transport_modules():
1534.7.70 by abentley
Fix bug when no paramiko
1111
            try:
1112
                result.extend(self.get_transport_test_permutations(reduce(getattr, 
1113
                    (module).split('.')[1:],
1185.71.1 by John Arbash Meinel
Allow selftest to run, even if we can't load a transport.
1114
                     __import__(module))))
1185.62.24 by John Arbash Meinel
Changing the exception that sftp.py throws when it can't find paramiko, so that the test suite can handle it.
1115
            except errors.DependencyNotPresent, e:
1116
                # Continue even if a dependency prevents us 
1117
                # from running this test
1534.7.70 by abentley
Fix bug when no paramiko
1118
                pass
1530.1.11 by Robert Collins
Push the transport permutations list into each transport module allowing for automatic testing of new modules that are registered as transports.
1119
        return result
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
1120
1121
1122
class TransportLogger(object):
1123
    """Adapt a transport to get clear logging data on api calls.
1124
    
1125
    Feel free to extend to log whatever calls are of interest.
1126
    """
1127
1128
    def __init__(self, adapted):
1129
        self._adapted = adapted
1130
        self._calls = []
1131
1132
    def get(self, name):
1133
        self._calls.append((name,))
1134
        return self._adapted.get(name)
1135
1136
    def __getattr__(self, name):
1137
        """Thunk all undefined access through to self._adapted."""
1138
        # raise AttributeError, name 
1139
        return getattr(self._adapted, name)
1140
1141
    def readv(self, name, offsets):
1142
        self._calls.append((name, offsets))
1143
        return self._adapted.readv(name, offsets)
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
1144
        
1145
1185.16.81 by mbp at sourcefrog
[merge] robert
1146
# None is the default transport, for things with no url scheme
1185.16.79 by Martin Pool
Load transports when they're first used.
1147
register_lazy_transport(None, 'bzrlib.transport.local', 'LocalTransport')
1148
register_lazy_transport('file://', 'bzrlib.transport.local', 'LocalTransport')
1149
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport')
1540.3.23 by Martin Pool
Allow urls like http+pycurl://host/ to use a particular impl
1150
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
1540.3.26 by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet
1151
                        'HttpTransport_urllib')
1540.3.23 by Martin Pool
Allow urls like http+pycurl://host/ to use a particular impl
1152
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
1540.3.26 by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet
1153
                        'HttpTransport_urllib')
1154
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
1155
                        'PyCurlTransport')
1156
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
1157
                        'PyCurlTransport')
1158
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
1159
                        'HttpTransport_urllib')
1160
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
1161
                        'HttpTransport_urllib')
1540.3.7 by Martin Pool
Prepare to select a transport depending on what dependencies can be satisfied.
1162
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
1163
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
1185.36.4 by Daniel Silverstone
Add FTP transport
1164
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')
1165
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport')
1685.1.41 by John Arbash Meinel
memory is now memory://, need to fix the test cases.
1166
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1167
register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator')
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
1168
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1169
register_lazy_transport('vfat+',
1608.2.4 by Martin Pool
[broken] Add FakeFVATTransport
1170
                        'bzrlib.transport.fakevfat',
1171
                        'FakeVFATTransportDecorator')
1910.19.1 by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used
1172
register_lazy_transport('bzr://',
1173
                        'bzrlib.transport.smart',
1174
                        'SmartTCPTransport')
1910.19.3 by Andrew Bennetts
Add SSH support.
1175
register_lazy_transport('bzr+ssh://',
1176
                        'bzrlib.transport.smart',
1177
                        'SmartSSHTransport')