~bzr-pqm/bzr/bzr.dev

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?
168
            raise errors.TransportError('%s: invalid port number' % port)
169
    host = urllib.unquote(host)
170
171
    path = urllib.unquote(path)
172
173
    return (scheme, username, password, host, port, path)
174
175
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
176
class _CoalescedOffset(object):
177
    """A data container for keeping track of coalesced offsets."""
178
179
    __slots__ = ['start', 'length', 'ranges']
180
181
    def __init__(self, start, length, ranges):
182
        self.start = start
183
        self.length = length
184
        self.ranges = ranges
185
186
    def __cmp__(self, other):
187
        return cmp((self.start, self.length, self.ranges),
188
                   (other.start, other.length, other.ranges))
189
190
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
191
class Transport(object):
192
    """This class encapsulates methods for retrieving or putting a file
193
    from/to a storage location.
194
195
    Most functions have a _multi variant, which allows you to queue up
196
    multiple requests. They generally have a dumb base implementation 
197
    which just iterates over the arguments, but smart Transport
198
    implementations can do pipelining.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
199
    In general implementations should support having a generator or a list
200
    as an argument (ie always iterate, never index)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
201
    """
202
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
203
    # implementations can override this if it is more efficient
204
    # for them to combine larger read chunks together
1864.5.4 by John Arbash Meinel
play around with tuning the partial reads.
205
    _max_readv_combine = 50
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
206
    # It is better to read this much more data in order, rather
207
    # than doing another seek. Even for the local filesystem,
208
    # there is a benefit in just reading.
209
    # TODO: jam 20060714 Do some real benchmarking to figure out
210
    #       where the biggest benefit between combining reads and
1864.5.8 by John Arbash Meinel
Cleanup and NEWS
211
    #       and seeking is. Consider a runtime auto-tune.
1864.5.4 by John Arbash Meinel
play around with tuning the partial reads.
212
    _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.
213
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
214
    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.
215
        super(Transport, self).__init__()
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
216
        self.base = base
217
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
218
    def _translate_error(self, e, path, raise_generic=True):
219
        """Translate an IOError or OSError into an appropriate bzr error.
220
221
        This handles things like ENOENT, ENOTDIR, EEXIST, and EACCESS
222
        """
223
        if hasattr(e, 'errno'):
224
            if e.errno in (errno.ENOENT, errno.ENOTDIR):
225
                raise errors.NoSuchFile(path, extra=e)
1185.31.58 by John Arbash Meinel
Updating for new transport tests so that they pass on win32
226
            # I would rather use errno.EFOO, but there doesn't seem to be
227
            # any matching for 267
228
            # This is the error when doing a listdir on a file:
229
            # WindowsError: [Errno 267] The directory name is invalid
230
            if sys.platform == 'win32' and e.errno in (errno.ESRCH, 267):
231
                raise errors.NoSuchFile(path, extra=e)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
232
            if e.errno == errno.EEXIST:
233
                raise errors.FileExists(path, extra=e)
234
            if e.errno == errno.EACCES:
235
                raise errors.PermissionDenied(path, extra=e)
1553.5.10 by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory
236
            if e.errno == errno.ENOTEMPTY:
237
                raise errors.DirectoryNotEmpty(path, extra=e)
1558.10.1 by Aaron Bentley
Handle lockdirs over NFS properly
238
            if e.errno == errno.EBUSY:
239
                raise errors.ResourceBusy(path, extra=e)
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
240
        if raise_generic:
241
            raise errors.TransportError(orig_error=e)
242
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
243
    def clone(self, offset=None):
244
        """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.
245
        using a subdirectory or parent directory. This allows connections 
246
        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.
247
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
248
        raise NotImplementedError(self.clone)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
249
907.1.32 by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate.
250
    def should_cache(self):
251
        """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.
252
        """
907.1.32 by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate.
253
        return False
907.1.22 by John Arbash Meinel
Fixed some encoding issues, added is_remote function for Transport objects.
254
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
255
    def _pump(self, from_file, to_file):
256
        """Most children will need to copy from one file-like 
257
        object or string to another one.
258
        This just gives them something easy to call.
259
        """
1948.3.8 by Vincent LADEUIL
_pump accepts strings finally :)
260
        if isinstance(from_file, basestring):
261
            to_file.write(from_file)
262
        else:
263
            pumpfile(from_file, to_file)
264
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
265
    def _get_total(self, multi):
266
        """Try to figure out how many entries are in multi,
267
        but if not possible, return None.
268
        """
269
        try:
270
            return len(multi)
271
        except TypeError: # We can't tell how many, because relpaths is a generator
272
            return None
273
274
    def _update_pb(self, pb, msg, count, total):
275
        """Update the progress bar based on the current count
276
        and total available, total may be None if it was
277
        not possible to determine.
278
        """
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
279
        if pb is None:
280
            return
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
281
        if total is None:
282
            pb.update(msg, count, count+1)
283
        else:
284
            pb.update(msg, count, total)
285
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
286
    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.
287
        """Iterate over all entries in multi, passing them to func,
288
        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.
289
290
        :param expand:  If True, the entries will be passed to the function
291
                        by expanding the tuple. If False, it will be passed
292
                        as a single parameter.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
293
        """
294
        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.
295
        result = []
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
296
        count = 0
297
        for entry in multi:
298
            self._update_pb(pb, msg, count, total)
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
299
            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.
300
                result.append(func(*entry))
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
301
            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.
302
                result.append(func(entry))
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
303
            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.
304
        return tuple(result)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
305
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
306
    def abspath(self, relpath):
307
        """Return the full url to the given relative path.
308
        This can be supplied with a string or a list
1442.1.44 by Robert Collins
Many transport related tweaks:
309
310
        XXX: Robert Collins 20051016 - is this really needed in the public
311
             interface ?
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
312
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
313
        raise NotImplementedError(self.abspath)
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
314
315
    def relpath(self, abspath):
316
        """Return the local path portion from a given absolute path.
1442.1.44 by Robert Collins
Many transport related tweaks:
317
318
        This default implementation is not suitable for filesystems with
319
        aliasing, such as that given by symlinks, where a path may not 
320
        start with our base, but still be a relpath once aliasing is 
321
        resolved.
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
322
        """
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
323
        # TODO: This might want to use bzrlib.osutils.relpath
324
        #       but we have to watch out because of the prefix issues
1530.1.3 by Robert Collins
transport implementations now tested consistently.
325
        if not (abspath == self.base[:-1] or abspath.startswith(self.base)):
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
326
            raise errors.PathNotChild(abspath, self.base)
1442.1.44 by Robert Collins
Many transport related tweaks:
327
        pl = len(self.base)
1530.1.3 by Robert Collins
transport implementations now tested consistently.
328
        return abspath[pl:].strip('/')
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
329
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
330
    def local_abspath(self, relpath):
331
        """Return the absolute path on the local filesystem.
332
333
        This function will only be defined for Transports which have a
334
        physical local filesystem representation.
335
        """
1685.1.11 by John Arbash Meinel
Not all of the registered transports use :// as part of their path, specifically memory:/
336
        # 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
337
        raise errors.TransportNotPossible('This is not a LocalTransport,'
338
            ' so there is no local representation for a path')
339
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
340
    def has(self, relpath):
1442.1.44 by Robert Collins
Many transport related tweaks:
341
        """Does the file relpath exist?
342
        
343
        Note that some transports MAY allow querying on directories, but this
1553.5.66 by Martin Pool
doc
344
        is not part of the protocol.  In other words, the results of 
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
345
        t.has("a_directory_name") are undefined.
1442.1.44 by Robert Collins
Many transport related tweaks:
346
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
347
        raise NotImplementedError(self.has)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
348
907.1.36 by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class.
349
    def has_multi(self, relpaths, pb=None):
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
350
        """Return True/False for each entry in relpaths"""
351
        total = self._get_total(relpaths)
352
        count = 0
353
        for relpath in relpaths:
907.1.36 by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class.
354
            self._update_pb(pb, 'has', count, total)
907.1.34 by John Arbash Meinel
Fixing append(), cleaning up function locations.
355
            yield self.has(relpath)
356
            count += 1
357
1185.16.155 by John Arbash Meinel
Added a has_any function to the Transport API
358
    def has_any(self, relpaths):
359
        """Return True if any of the paths exist."""
360
        for relpath in relpaths:
361
            if self.has(relpath):
362
                return True
363
        return False
364
1442.1.44 by Robert Collins
Many transport related tweaks:
365
    def iter_files_recursive(self):
366
        """Iter the relative paths of files in the transports sub-tree.
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
367
368
        *NOTE*: This only lists *files*, not subdirectories!
1442.1.44 by Robert Collins
Many transport related tweaks:
369
        
370
        As with other listing functions, only some transports implement this,.
371
        you may check via is_listable to determine if it will.
372
        """
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
373
        raise errors.TransportNotPossible("This transport has not "
1530.1.21 by Robert Collins
Review feedback fixes.
374
                                          "implemented iter_files_recursive "
1530.1.4 by Robert Collins
integrate Memory tests into transport interface tests.
375
                                          "(but must claim to be listable "
376
                                          "to trigger this error).")
1442.1.44 by Robert Collins
Many transport related tweaks:
377
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
378
    def get(self, relpath):
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
379
        """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
380
381
        :param relpath: The relative path to the file
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
382
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
383
        raise NotImplementedError(self.get)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
384
1955.3.3 by John Arbash Meinel
Implement and test 'get_bytes'
385
    def get_bytes(self, relpath):
386
        """Get a raw string of the bytes for a file at the given location.
387
388
        :param relpath: The relative path to the file
389
        """
390
        return self.get(relpath).read()
391
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
392
    def readv(self, relpath, offsets):
393
        """Get parts of the file at the given relative path.
394
395
        :offsets: A list of (offset, size) tuples.
396
        :return: A list or generator of (offset, data) tuples
397
        """
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
398
        if not offsets:
1594.2.16 by Robert Collins
Coalesce readv requests on file based transports.
399
            return
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
400
1864.5.7 by John Arbash Meinel
remove disable prefetch support
401
        fp = self.get(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.
402
        return self._seek_and_read(fp, offsets)
403
404
    def _seek_and_read(self, fp, offsets):
405
        """An implementation of readv that uses fp.seek and fp.read.
406
407
        This uses _coalesce_offsets to issue larger reads and fewer seeks.
408
409
        :param fp: A file-like object that supports seek() and read(size)
410
        :param offsets: A list of offsets to be read from the given file.
411
        :return: yield (pos, data) tuples for each request
412
        """
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
413
        # We are going to iterate multiple times, we need a list
414
        offsets = list(offsets)
415
        sorted_offsets = sorted(offsets)
416
417
        # 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.
418
        offset_stack = iter(offsets)
419
        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
420
        coalesced = self._coalesce_offsets(sorted_offsets,
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
421
                               limit=self._max_readv_combine,
422
                               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
423
424
        # Cache the results, but only until they have been fulfilled
425
        data_map = {}
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
426
        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.
427
            # TODO: jam 20060724 it might be faster to not issue seek if 
428
            #       we are already at the right location. This should be
429
            #       benchmarked.
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
430
            fp.seek(c_offset.start)
431
            data = fp.read(c_offset.length)
432
            for suboffset, subsize in c_offset.ranges:
433
                key = (c_offset.start+suboffset, subsize)
434
                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.
435
1864.5.8 by John Arbash Meinel
Cleanup and NEWS
436
            # 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.
437
            while cur_offset_and_size in data_map:
438
                this_data = data_map.pop(cur_offset_and_size)
439
                yield cur_offset_and_size[0], this_data
440
                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.
441
442
    @staticmethod
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
443
    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.
444
        """Yield coalesced offsets.
445
446
        With a long list of neighboring requests, combine them
447
        into a single large request, while retaining the original
448
        offsets.
449
        Turns  [(15, 10), (25, 10)] => [(15, 20, [(0, 10), (10, 10)])]
450
451
        :param offsets: A list of (start, length) pairs
452
        :param limit: Only combine a maximum of this many pairs
453
                      Some transports penalize multiple reads more than
454
                      others, and sometimes it is better to return early.
455
                      0 means no limit
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
456
        :param fudge_factor: All transports have some level of 'it is
457
                better to read some more data and throw it away rather 
458
                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.
459
        :return: yield _CoalescedOffset objects, which have members for wher
460
                to start, how much to read, and how to split those 
461
                chunks back up
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
462
        """
463
        last_end = None
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
464
        cur = _CoalescedOffset(None, None, [])
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
465
466
        for start, size in offsets:
467
            end = start + size
468
            if (last_end is not None 
1864.5.3 by John Arbash Meinel
Allow collapsing ranges even if they are just 'close'
469
                and start <= last_end + fudge_factor
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
470
                and start >= cur.start
471
                and (limit <= 0 or len(cur.ranges) < limit)):
472
                cur.length = end - cur.start
473
                cur.ranges.append((start-cur.start, size))
1594.2.16 by Robert Collins
Coalesce readv requests on file based transports.
474
            else:
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
475
                if cur.start is not None:
476
                    yield cur
477
                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.
478
            last_end = end
479
1864.5.9 by John Arbash Meinel
Switch to returning an object to make the api more understandable.
480
        if cur.start is not None:
481
            yield cur
1864.5.1 by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test.
482
483
        return
1594.2.5 by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support.
484
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
485
    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.
486
        """Get a list of file-like objects, one for each entry in relpaths.
487
488
        :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.
489
        :param pb:  An optional ProgressBar for indicating percent done.
490
        :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.
491
        """
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
492
        # TODO: Consider having this actually buffer the requests,
493
        # in the default mode, it probably won't give worse performance,
494
        # and all children wouldn't have to implement buffering
907.1.16 by John Arbash Meinel
Fixing a few cut&paste typos.
495
        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.
496
        count = 0
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
497
        for relpath in relpaths:
907.1.16 by John Arbash Meinel
Fixing a few cut&paste typos.
498
            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.
499
            yield self.get(relpath)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
500
            count += 1
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
501
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
502
    @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.
503
    def put(self, relpath, f, mode=None):
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
504
        """Copy the file-like or string object into the location.
907.1.20 by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8
505
506
        :param relpath: Location to put the contents, relative to base.
507
        :param f:       File-like or string object.
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
508
        :param mode: The mode for the newly created file, 
509
                     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.
510
        """
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
511
        if isinstance(f, str):
512
            return self.put_bytes(relpath, f, mode=mode)
513
        else:
514
            return self.put_file(relpath, f, mode=mode)
515
516
    def put_file(self, relpath, f, mode=None):
517
        """Copy the file-like object into the location.
518
519
        :param relpath: Location to put the contents, relative to base.
520
        :param f:       File-like object.
521
        :param mode: The mode for the newly created file,
522
                     None means just use the default.
523
        """
524
        # We would like to mark this as NotImplemented, but most likely
525
        # transports have defined it in terms of the old api.
526
        symbol_versioning.warn('Transport %s should implement put_file,'
527
                               ' rather than implementing put() as of'
528
                               ' version 0.11.'
529
                               % (self.__class__.__name__,),
530
                               DeprecationWarning)
531
        return self.put(relpath, f, mode=mode)
532
        #raise NotImplementedError(self.put_file)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
533
1955.3.1 by John Arbash Meinel
Add put_bytes() and a base-level implementation for it
534
    def put_bytes(self, relpath, bytes, mode=None):
535
        """Atomically put the supplied bytes into the given location.
536
537
        :param relpath: The location to put the contents, relative to the
538
            transport base.
539
        :param bytes: A bytestring of data.
540
        :param mode: Create the file with the given mode.
541
        :return: None
542
        """
543
        assert isinstance(bytes, str), \
544
            'bytes must be a plain string, not %s' % type(bytes)
1955.3.6 by John Arbash Meinel
Lots of deprecation warnings, but no errors
545
        return self.put_file(relpath, StringIO(bytes), mode=mode)
1955.3.1 by John Arbash Meinel
Add put_bytes() and a base-level implementation for it
546
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
547
    @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.
548
    def put_multi(self, files, mode=None, pb=None):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
549
        """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.
550
551
        :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.
552
        :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.
553
        :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.
554
        :return: The number of files copied.
555
        """
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
556
        def put(path, f):
1955.3.7 by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves
557
            if isinstance(f, str):
558
                self.put_bytes(path, f, mode=mode)
559
            else:
560
                self.put_file(path, f, 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.
561
        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.
562
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
563
    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.
564
        """Create a directory at the given path."""
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
565
        raise NotImplementedError(self.mkdir)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
566
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
567
    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
568
        """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.
569
        def mkdir(path):
570
            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.
571
        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
572
1755.3.1 by Robert Collins
Tune the time to build our kernel_like tree : make LocalTransport.put faster, AtomicFile faster, LocalTransport.append faster.
573
    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
574
        """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.
575
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
576
        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.
577
        
578
        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.
579
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
580
        raise NotImplementedError(self.append)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
581
1955.3.2 by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append
582
    def append_bytes(self, relpath, bytes, mode=None):
583
        """Append the text in the string object to the supplied location.
584
585
        returns the length of relpath before the content was written to it.
586
        
587
        If the file does not exist, it is created with the supplied mode.
588
        """
589
        assert isinstance(bytes, str), \
590
            'bytes must be a plain string, not %s' % type(bytes)
591
        return self.append(relpath, StringIO(bytes), mode=mode)
592
1185.11.19 by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings.
593
    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.
594
        """Append the text in each file-like or string object to
595
        the supplied location.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
596
597
        :param files: A set of (path, f) entries
598
        :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.
599
        """
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
600
        return self._iterate_over(files, self.append, pb, 'append', expand=True)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
601
602
    def copy(self, rel_from, rel_to):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
603
        """Copy the item at rel_from to the location at rel_to.
604
        
605
        Override this for efficiency if a specific transport can do it 
606
        faster than this default implementation.
607
        """
608
        self.put(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.
609
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
610
    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.
611
        """Copy a bunch of entries.
612
        
613
        :param relpaths: A list of tuples of the form [(from, to), (from, to),...]
614
        """
615
        # This is the non-pipelined implementation, so that
616
        # implementors don't have to implement everything.
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
617
        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.
618
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
619
    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.
620
        """Copy a set of entries from self into another Transport.
621
622
        :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.
623
        :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
624
        TODO: This interface needs to be updated so that the target location
625
              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.
626
        """
627
        # The dummy implementation just does a simple get + put
628
        def copy_entry(path):
1185.58.2 by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work.
629
            other.put(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.
630
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.
631
        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.
632
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
633
    def copy_tree(self, from_relpath, to_relpath):
634
        """Copy a subtree from one relpath to another.
635
636
        If a faster implementation is available, specific transports should 
637
        implement it.
638
        """
639
        source = self.clone(from_relpath)
640
        self.mkdir(to_relpath)
641
        target = self.clone(to_relpath)
642
        files = []
643
        directories = ['.']
644
        while directories:
645
            dir = directories.pop()
646
            if dir != '.':
647
                target.mkdir(dir)
648
            for path in source.list_dir(dir):
649
                path = dir + '/' + path
650
                stat = source.stat(path)
651
                if S_ISDIR(stat.st_mode):
652
                    directories.append(path)
653
                else:
654
                    files.append(path)
655
        source.copy_to(files, target)
656
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
657
    def rename(self, rel_from, rel_to):
658
        """Rename a file or directory.
659
660
        This *must* fail if the destination is a nonempty directory - it must
661
        not automatically remove it.  It should raise DirectoryNotEmpty, or
662
        some other PathError if the case can't be specifically detected.
663
664
        If the destination is an empty directory or a file this function may
665
        either fail or succeed, depending on the underlying transport.  It
666
        should not attempt to remove the destination if overwriting is not the
667
        native transport behaviour.  If at all possible the transport should
668
        ensure that the rename either completes or not, without leaving the
669
        destination deleted and the new file not moved in place.
670
671
        This is intended mainly for use in implementing LockDir.
672
        """
673
        # transports may need to override this
1553.5.17 by Martin Pool
Transport.rename should be unimplemented in base class
674
        raise NotImplementedError(self.rename)
1553.5.13 by Martin Pool
New Transport.rename that mustn't overwrite
675
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
676
    def move(self, rel_from, rel_to):
1530.1.3 by Robert Collins
transport implementations now tested consistently.
677
        """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
678
679
        The destination is deleted if possible, even if it's a non-empty
680
        directory tree.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
681
        
682
        If a transport can directly implement this it is suggested that
683
        it do so for efficiency.
684
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
685
        if S_ISDIR(self.stat(rel_from).st_mode):
686
            self.copy_tree(rel_from, rel_to)
687
            self.delete_tree(rel_from)
688
        else:
689
            self.copy(rel_from, rel_to)
690
            self.delete(rel_from)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
691
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
692
    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.
693
        """Move a bunch of entries.
694
        
695
        :param relpaths: A list of tuples of the form [(from1, to1), (from2, to2),...]
696
        """
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
697
        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.
698
699
    def move_multi_to(self, relpaths, rel_to):
700
        """Move a bunch of entries to a single location.
701
        This differs from move_multi in that you give a list of from, and
702
        a single destination, rather than multiple destinations.
703
704
        :param relpaths: A list of relative paths [from1, from2, from3, ...]
705
        :param rel_to: A directory where each entry should be placed.
706
        """
707
        # This is not implemented, because you need to do special tricks to
708
        # 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.
709
        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.
710
711
    def delete(self, relpath):
712
        """Delete the item at relpath"""
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
713
        raise NotImplementedError(self.delete)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
714
907.1.28 by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function.
715
    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.
716
        """Queue up a bunch of deletes to be done.
717
        """
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
718
        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.
719
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
720
    def delete_tree(self, relpath):
721
        """Delete an entire tree. This may require a listable transport."""
722
        subtree = self.clone(relpath)
723
        files = []
724
        directories = ['.']
725
        pending_rmdirs = []
726
        while directories:
727
            dir = directories.pop()
728
            if dir != '.':
729
                pending_rmdirs.append(dir)
730
            for path in subtree.list_dir(dir):
731
                path = dir + '/' + path
732
                stat = subtree.stat(path)
733
                if S_ISDIR(stat.st_mode):
734
                    directories.append(path)
735
                else:
736
                    files.append(path)
737
        subtree.delete_multi(files)
738
        pending_rmdirs.reverse()
739
        for dir in pending_rmdirs:
740
            subtree.rmdir(dir)
741
        self.rmdir(relpath)
742
1534.5.7 by Robert Collins
Start factoring out the upgrade policy logic.
743
    def __repr__(self):
744
        return "<%s.%s url=%s>" % (self.__module__, self.__class__.__name__, self.base)
745
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
746
    def stat(self, relpath):
747
        """Return the stat information for a file.
748
        WARNING: This may not be implementable for all protocols, so use
749
        sparingly.
1442.1.44 by Robert Collins
Many transport related tweaks:
750
        NOTE: This returns an object with fields such as 'st_size'. It MAY
751
        or MAY NOT return the literal result of an os.stat() call, so all
752
        access should be via named fields.
753
        ALSO NOTE: Stats of directories may not be supported on some 
754
        transports.
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
755
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
756
        raise NotImplementedError(self.stat)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
757
1534.4.15 by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports.
758
    def rmdir(self, relpath):
759
        """Remove a directory at the given path."""
760
        raise NotImplementedError
761
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
762
    def stat_multi(self, relpaths, pb=None):
763
        """Stat multiple files and return the information.
764
        """
765
        #TODO:  Is it worth making this a generator instead of a
766
        #       returning a list?
767
        stats = []
768
        def gather(path):
769
            stats.append(self.stat(path))
770
907.1.14 by John Arbash Meinel
Handling some transport functions which take only a single argument.
771
        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.
772
        return stats
773
1400.1.1 by Robert Collins
implement a basic test for the ui branch command from http servers
774
    def listable(self):
775
        """Return True if this store supports listing."""
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
776
        raise NotImplementedError(self.listable)
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
777
778
    def list_dir(self, relpath):
779
        """Return a list of all files at the given location.
780
        WARNING: many transports do not support this, so trying avoid using
781
        it if at all possible.
782
        """
1185.31.44 by John Arbash Meinel
Cleaned up Exceptions for all transports.
783
        raise errors.TransportNotPossible("This transport has not "
1530.1.21 by Robert Collins
Review feedback fixes.
784
                                          "implemented list_dir "
1530.1.3 by Robert Collins
transport implementations now tested consistently.
785
                                          "(but must claim to be listable "
786
                                          "to trigger this error).")
907.1.1 by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer.
787
907.1.24 by John Arbash Meinel
Remote functionality work.
788
    def lock_read(self, relpath):
789
        """Lock the given file for shared (read) access.
790
        WARNING: many transports do not support this, so trying avoid using it
791
792
        :return: A lock object, which should contain an unlock() function.
793
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
794
        raise NotImplementedError(self.lock_read)
907.1.24 by John Arbash Meinel
Remote functionality work.
795
796
    def lock_write(self, relpath):
797
        """Lock the given file for exclusive (write) access.
798
        WARNING: many transports do not support this, so trying avoid using it
799
800
        :return: A lock object, which should contain an unlock() function.
801
        """
1540.3.1 by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib.
802
        raise NotImplementedError(self.lock_write)
907.1.24 by John Arbash Meinel
Remote functionality work.
803
1530.1.3 by Robert Collins
transport implementations now tested consistently.
804
    def is_readonly(self):
805
        """Return true if this connection cannot be written to."""
806
        return False
807
1608.2.7 by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity
808
    def _can_roundtrip_unix_modebits(self):
1608.2.5 by Martin Pool
Add Transport.supports_unix_modebits, so tests can
809
        """Return true if this transport can store and retrieve unix modebits.
810
811
        (For example, 0700 to make a directory owner-private.)
812
        
813
        Note: most callers will not want to switch on this, but should rather 
814
        just try and set permissions and let them be either stored or not.
815
        This is intended mainly for the use of the test suite.
816
        
817
        Warning: this is not guaranteed to be accurate as sometimes we can't 
818
        be sure: for example with vfat mounted on unix, or a windows sftp
819
        server."""
820
        # TODO: Perhaps return a e.g. TransportCharacteristics that can answer
821
        # several questions about the transport.
822
        return False
823
907.1.24 by John Arbash Meinel
Remote functionality work.
824
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
825
# jam 20060426 For compatibility we copy the functions here
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
826
# TODO: The should be marked as deprecated
827
urlescape = urlutils.escape
828
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
829
_urlRE = re.compile(r'^(?P<proto>[^:/\\]+)://(?P<path>.*)$')
830
831
1393.2.4 by John Arbash Meinel
All tests pass.
832
def get_transport(base):
1185.70.3 by Martin Pool
Various updates to make storage branch mergeable:
833
    """Open a transport to access a URL or directory.
834
835
    base is either a URL or a directory name.  
836
    """
1540.3.8 by Martin Pool
Some support for falling back between transport implementations.
837
    # TODO: give a better error if base looks like a url but there's no
838
    # handler for the scheme?
907.1.45 by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary.
839
    global _protocol_handlers
907.1.13 by John Arbash Meinel
Fixed bzr root.
840
    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:/
841
        base = '.'
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
842
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
843
    last_err = None
844
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
845
    def convert_path_to_url(base, error_str):
846
        m = _urlRE.match(base)
847
        if m:
848
            # This looks like a URL, but we weren't able to 
849
            # 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
850
            raise errors.UnsupportedProtocol(base, last_err)
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
851
        # 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
852
        new_base = urlutils.local_path_to_url(base)
1908.3.1 by Carl Friedrich Bolz
Clean up some mutter() calls.
853
        # 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
854
        return new_base
855
856
    # Catch any URLs which are passing Unicode rather than ASCII
857
    try:
858
        base = base.encode('ascii')
859
    except UnicodeError:
860
        # Only local paths can be Unicode
861
        base = convert_path_to_url(base,
862
            '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:/
863
    
864
    for proto, factory_list in _protocol_handlers.iteritems():
865
        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
866
            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:/
867
            if t:
868
                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
869
1685.1.33 by John Arbash Meinel
Be more of a Nazi about URLs not being unicode
870
    # We tried all the different protocols, now try one last time
871
    # as a local protocol
872
    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:/
873
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
874
    # 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
875
    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
876
877
878
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
879
    last_err = None
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
880
    for factory in factory_list:
881
        try:
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
882
            return factory(base), None
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
883
        except DependencyNotPresent, e:
884
            mutter("failed to instantiate transport %r for %r: %r" %
885
                    (factory, base, e))
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
886
            last_err = e
1540.3.12 by Martin Pool
Multiple transports can be registered for any protocol, and they are
887
            continue
1843.1.1 by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info
888
    return None, last_err
1185.16.81 by mbp at sourcefrog
[merge] robert
889
1185.16.78 by Martin Pool
- load paramiko sftp transport by default
890
1530.1.3 by Robert Collins
transport implementations now tested consistently.
891
class Server(object):
1530.1.21 by Robert Collins
Review feedback fixes.
892
    """A Transport Server.
893
    
894
    The Server interface provides a server for a given transport. We use
895
    these servers as loopback testing tools. For any given transport the
896
    Servers it provides must either allow writing, or serve the contents
897
    of os.getcwdu() at the time setUp is called.
898
    
899
    Note that these are real servers - they must implement all the things
900
    that we want bzr transports to take advantage of.
901
    """
1530.1.3 by Robert Collins
transport implementations now tested consistently.
902
903
    def setUp(self):
904
        """Setup the server to service requests."""
905
906
    def tearDown(self):
907
        """Remove the server and cleanup any resources it owns."""
908
909
    def get_url(self):
1530.1.21 by Robert Collins
Review feedback fixes.
910
        """Return a url for this server.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
911
        
912
        If the transport does not represent a disk directory (i.e. it is 
1530.1.21 by Robert Collins
Review feedback fixes.
913
        a database like svn, or a memory only transport, it should return
1530.1.3 by Robert Collins
transport implementations now tested consistently.
914
        a connection to a newly established resource for this Server.
1530.1.21 by Robert Collins
Review feedback fixes.
915
        Otherwise it should return a url that will provide access to the path
916
        that was os.getcwdu() when setUp() was called.
1530.1.3 by Robert Collins
transport implementations now tested consistently.
917
        
918
        Subsequent calls will return the same resource.
919
        """
920
        raise NotImplementedError
921
1530.1.9 by Robert Collins
Test bogus urls with http in the new infrastructure.
922
    def get_bogus_url(self):
923
        """Return a url for this protocol, that will fail to connect."""
924
        raise NotImplementedError
925
1530.1.3 by Robert Collins
transport implementations now tested consistently.
926
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
927
class TransportTestProviderAdapter(object):
1530.1.21 by Robert Collins
Review feedback fixes.
928
    """A tool to generate a suite testing all transports for a single test.
929
930
    This is done by copying the test once for each transport and injecting
931
    the transport_class and transport_server classes into each copy. Each copy
932
    is also given a new id() to make it easy to identify.
933
    """
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
934
935
    def adapt(self, test):
936
        result = TestSuite()
937
        for klass, server_factory in self._test_permutations():
938
            new_test = deepcopy(test)
939
            new_test.transport_class = klass
940
            new_test.transport_server = server_factory
1530.1.3 by Robert Collins
transport implementations now tested consistently.
941
            def make_new_test_id():
942
                new_id = "%s(%s)" % (new_test.id(), server_factory.__name__)
943
                return lambda: new_id
944
            new_test.id = make_new_test_id()
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
945
            result.addTest(new_test)
946
        return result
947
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.
948
    def get_transport_test_permutations(self, module):
949
        """Get the permutations module wants to have tested."""
1540.3.6 by Martin Pool
[merge] update from bzr.dev
950
        if not hasattr(module, 'get_test_permutations'):
951
            warning("transport module %s doesn't provide get_test_permutations()"
952
                    % module.__name__)
953
            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.
954
        return module.get_test_permutations()
955
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
956
    def _test_permutations(self):
957
        """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.
958
        result = []
959
        for module in _get_transport_modules():
1534.7.70 by abentley
Fix bug when no paramiko
960
            try:
961
                result.extend(self.get_transport_test_permutations(reduce(getattr, 
962
                    (module).split('.')[1:],
1185.71.1 by John Arbash Meinel
Allow selftest to run, even if we can't load a transport.
963
                     __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.
964
            except errors.DependencyNotPresent, e:
965
                # Continue even if a dependency prevents us 
966
                # from running this test
1534.7.70 by abentley
Fix bug when no paramiko
967
                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.
968
        return result
1594.2.24 by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching.
969
970
971
class TransportLogger(object):
972
    """Adapt a transport to get clear logging data on api calls.
973
    
974
    Feel free to extend to log whatever calls are of interest.
975
    """
976
977
    def __init__(self, adapted):
978
        self._adapted = adapted
979
        self._calls = []
980
981
    def get(self, name):
982
        self._calls.append((name,))
983
        return self._adapted.get(name)
984
985
    def __getattr__(self, name):
986
        """Thunk all undefined access through to self._adapted."""
987
        # raise AttributeError, name 
988
        return getattr(self._adapted, name)
989
990
    def readv(self, name, offsets):
991
        self._calls.append((name, offsets))
992
        return self._adapted.readv(name, offsets)
1530.1.1 by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter.
993
        
994
1185.16.81 by mbp at sourcefrog
[merge] robert
995
# None is the default transport, for things with no url scheme
1185.16.79 by Martin Pool
Load transports when they're first used.
996
register_lazy_transport(None, 'bzrlib.transport.local', 'LocalTransport')
997
register_lazy_transport('file://', 'bzrlib.transport.local', 'LocalTransport')
998
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
999
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
1540.3.26 by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet
1000
                        'HttpTransport_urllib')
1540.3.23 by Martin Pool
Allow urls like http+pycurl://host/ to use a particular impl
1001
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
1540.3.26 by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet
1002
                        'HttpTransport_urllib')
1003
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
1004
                        'PyCurlTransport')
1005
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
1006
                        'PyCurlTransport')
1007
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
1008
                        'HttpTransport_urllib')
1009
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
1010
                        'HttpTransport_urllib')
1540.3.7 by Martin Pool
Prepare to select a transport depending on what dependencies can be satisfied.
1011
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
1012
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
1185.36.4 by Daniel Silverstone
Add FTP transport
1013
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')
1014
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.
1015
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
1534.4.9 by Robert Collins
Add a readonly decorator for transports.
1016
register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator')
1558.10.2 by Robert Collins
Refactor the FakeNFS support into a TransportDecorator.
1017
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
1608.2.4 by Martin Pool
[broken] Add FakeFVATTransport
1018
register_lazy_transport('vfat+', 
1019
                        'bzrlib.transport.fakevfat',
1020
                        'FakeVFATTransportDecorator')