2245.8.2
by Martin Pool
doc |
1 |
# Copyright (C) 2005, 2006, 2007 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 |
||
1996.3.6
by John Arbash Meinel
Find a few places that weren't importing their dependencies. |
29 |
from cStringIO import StringIO |
30 |
import re |
|
31 |
import sys |
|
32 |
||
33 |
from bzrlib.lazy_import import lazy_import |
|
34 |
lazy_import(globals(), """ |
|
1185.31.44
by John Arbash Meinel
Cleaned up Exceptions for all transports. |
35 |
import errno
|
1594.2.17
by Robert Collins
Better readv coalescing, now with test, and progress during knit index reading. |
36 |
from collections import deque
|
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
37 |
from copy import deepcopy
|
1773.4.1
by Martin Pool
Add pyflakes makefile target; fix many warnings |
38 |
from stat import S_ISDIR
|
1996.3.6
by John Arbash Meinel
Find a few places that weren't importing their dependencies. |
39 |
import unittest
|
1685.1.70
by Wouter van Heyst
working on get_parent, set_parent and relative urls, broken |
40 |
import urllib
|
1636.1.1
by Robert Collins
Fix calling relpath() and abspath() on transports at their root. |
41 |
import urlparse
|
1773.4.1
by Martin Pool
Add pyflakes makefile target; fix many warnings |
42 |
import warnings
|
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
43 |
|
1725.2.3
by Robert Collins
Remove import of pumpfile from inner loop of commit. |
44 |
import bzrlib
|
1955.3.6
by John Arbash Meinel
Lots of deprecation warnings, but no errors |
45 |
from bzrlib import (
|
46 |
errors,
|
|
47 |
osutils,
|
|
48 |
symbol_versioning,
|
|
49 |
urlutils,
|
|
50 |
)
|
|
1996.3.6
by John Arbash Meinel
Find a few places that weren't importing their dependencies. |
51 |
""") |
52 |
||
1955.3.6
by John Arbash Meinel
Lots of deprecation warnings, but no errors |
53 |
from bzrlib.symbol_versioning import ( |
54 |
deprecated_passed, |
|
55 |
deprecated_method, |
|
56 |
deprecated_function, |
|
1773.4.1
by Martin Pool
Add pyflakes makefile target; fix many warnings |
57 |
DEPRECATED_PARAMETER, |
1955.3.6
by John Arbash Meinel
Lots of deprecation warnings, but no errors |
58 |
zero_eight, |
59 |
zero_eleven, |
|
60 |
)
|
|
2164.2.21
by Vincent Ladeuil
Take bundles into account. |
61 |
from bzrlib.trace import ( |
62 |
note, |
|
63 |
mutter, |
|
64 |
warning, |
|
65 |
)
|
|
2241.2.1
by ghigo
Add the TransportRegistry class |
66 |
from bzrlib import registry |
2018.5.104
by Andrew Bennetts
Completely rework chrooted transports. |
67 |
|
68 |
||
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. |
69 |
def _get_protocol_handlers(): |
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
70 |
"""Return a dictionary of {urlprefix: [factory]}"""
|
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
71 |
return transport_list_registry |
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. |
72 |
|
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
73 |
|
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. |
74 |
def _set_protocol_handlers(new_handlers): |
75 |
"""Replace the current protocol handlers dictionary.
|
|
76 |
||
77 |
WARNING this will remove all build in protocols. Use with care.
|
|
78 |
"""
|
|
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
79 |
global transport_list_registry |
80 |
transport_list_registry = new_handlers |
|
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. |
81 |
|
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
82 |
|
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
83 |
def _clear_protocol_handlers(): |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
84 |
global transport_list_registry |
85 |
transport_list_registry = TransportListRegistry() |
|
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
86 |
|
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
87 |
|
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. |
88 |
def _get_transport_modules(): |
89 |
"""Return a list of the modules providing transports."""
|
|
90 |
modules = set() |
|
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
91 |
for prefix, factory_list in transport_list_registry.iteritems(): |
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
92 |
for factory in factory_list: |
2241.2.2
by ghigo
Create the TransportList class |
93 |
if hasattr(factory, "_module_name"): |
94 |
modules.add(factory._module_name) |
|
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
95 |
else: |
2241.2.2
by ghigo
Create the TransportList class |
96 |
modules.add(factory._obj.__module__) |
2018.5.104
by Andrew Bennetts
Completely rework chrooted transports. |
97 |
# Add chroot directly, because there is not handler registered for it.
|
98 |
modules.add('bzrlib.transport.chroot') |
|
1530.1.19
by Robert Collins
Make transport test adapter tests reliable. |
99 |
result = list(modules) |
100 |
result.sort() |
|
101 |
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. |
102 |
|
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
103 |
|
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
104 |
class TransportListRegistry(registry.Registry): |
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
105 |
"""A registry which simplifies tracking available Transports.
|
106 |
||
107 |
A registration of a new protocol requires two step:
|
|
108 |
1) register the prefix with the function register_transport( )
|
|
109 |
2) register the protocol provider with the function
|
|
110 |
register_transport_provider( ) ( and the "lazy" variant )
|
|
111 |
||
112 |
This in needed because:
|
|
113 |
a) a single provider can support multple protcol ( like the ftp
|
|
114 |
privider which supports both the ftp:// and the aftp:// protocols )
|
|
115 |
b) a single protocol can have multiple providers ( like the http://
|
|
116 |
protocol which is supported by both the urllib and pycurl privider )
|
|
117 |
"""
|
|
118 |
||
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
119 |
def register_transport_provider(self, key, obj): |
120 |
self.get(key).insert(0, registry._ObjectGetter(obj)) |
|
121 |
||
122 |
def register_lazy_transport_provider(self, key, module_name, member_name): |
|
123 |
self.get(key).insert(0, |
|
2241.2.1
by ghigo
Add the TransportRegistry class |
124 |
registry._LazyObjectGetter(module_name, member_name)) |
125 |
||
126 |
def register_transport(self, key, help=None, info=None): |
|
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
127 |
self.register(key, [], help, info) |
2241.2.1
by ghigo
Add the TransportRegistry class |
128 |
|
129 |
def set_default_transport(self, key=None): |
|
130 |
"""Return either 'key' or the default key if key is None"""
|
|
131 |
self._default_key = key |
|
132 |
||
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
133 |
|
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
134 |
transport_list_registry = TransportListRegistry( ) |
2241.2.1
by ghigo
Add the TransportRegistry class |
135 |
|
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
136 |
|
2241.2.1
by ghigo
Add the TransportRegistry class |
137 |
def register_transport_proto(prefix, help=None, info=None): |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
138 |
transport_list_registry.register_transport(prefix, help, info) |
2241.2.1
by ghigo
Add the TransportRegistry class |
139 |
|
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
140 |
|
2241.2.1
by ghigo
Add the TransportRegistry class |
141 |
def register_lazy_transport(prefix, module, classname): |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
142 |
if not prefix in transport_list_registry: |
2241.2.2
by ghigo
Create the TransportList class |
143 |
register_transport_proto(prefix) |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
144 |
transport_list_registry.register_lazy_transport_provider(prefix, module, classname) |
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
145 |
|
146 |
||
2241.2.1
by ghigo
Add the TransportRegistry class |
147 |
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER): |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
148 |
if not prefix in transport_list_registry: |
2241.2.2
by ghigo
Create the TransportList class |
149 |
register_transport_proto(prefix) |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
150 |
transport_list_registry.register_transport_provider(prefix, klass) |
2241.2.1
by ghigo
Add the TransportRegistry class |
151 |
|
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
152 |
|
1636.1.2
by Robert Collins
More review fixen to the relpath at '/' fixes. |
153 |
def register_urlparse_netloc_protocol(protocol): |
1636.1.1
by Robert Collins
Fix calling relpath() and abspath() on transports at their root. |
154 |
"""Ensure that protocol is setup to be used with urlparse netloc parsing."""
|
155 |
if protocol not in urlparse.uses_netloc: |
|
156 |
urlparse.uses_netloc.append(protocol) |
|
157 |
||
2241.3.4
by ghigo
Updates on the basis of John Arbash Meinel comments |
158 |
|
2241.3.5
by ghigo
update to the latest bzr.dev |
159 |
def unregister_transport(scheme, factory): |
160 |
"""Unregister a transport."""
|
|
161 |
l = transport_list_registry.get(scheme) |
|
162 |
for i in l: |
|
163 |
o = i.get_obj( ) |
|
164 |
if o == factory: |
|
165 |
transport_list_registry.get(scheme).remove(i) |
|
166 |
break
|
|
167 |
if len(l) == 0: |
|
168 |
transport_list_registry.remove(scheme) |
|
169 |
||
170 |
||
171 |
||
1707.3.4
by John Arbash Meinel
Moved most of sftp.split_url into a Transport function. |
172 |
def split_url(url): |
1685.1.69
by Wouter van Heyst
merge bzr.dev 1740 |
173 |
# 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. |
174 |
if isinstance(url, unicode): |
175 |
url = url.encode('utf-8') |
|
176 |
(scheme, netloc, path, params, |
|
177 |
query, fragment) = urlparse.urlparse(url, allow_fragments=False) |
|
178 |
username = password = host = port = None |
|
179 |
if '@' in netloc: |
|
180 |
username, host = netloc.split('@', 1) |
|
181 |
if ':' in username: |
|
182 |
username, password = username.split(':', 1) |
|
183 |
password = urllib.unquote(password) |
|
184 |
username = urllib.unquote(username) |
|
185 |
else: |
|
186 |
host = netloc |
|
187 |
||
188 |
if ':' in host: |
|
189 |
host, port = host.rsplit(':', 1) |
|
190 |
try: |
|
191 |
port = int(port) |
|
192 |
except ValueError: |
|
193 |
# TODO: Should this be ConnectionError?
|
|
1910.15.8
by Andrew Bennetts
Put url in 'invalid port number' message on a new line. |
194 |
raise errors.TransportError( |
195 |
'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. |
196 |
host = urllib.unquote(host) |
197 |
||
198 |
path = urllib.unquote(path) |
|
199 |
||
200 |
return (scheme, username, password, host, port, path) |
|
201 |
||
202 |
||
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
203 |
class _CoalescedOffset(object): |
204 |
"""A data container for keeping track of coalesced offsets."""
|
|
205 |
||
206 |
__slots__ = ['start', 'length', 'ranges'] |
|
207 |
||
208 |
def __init__(self, start, length, ranges): |
|
209 |
self.start = start |
|
210 |
self.length = length |
|
211 |
self.ranges = ranges |
|
212 |
||
213 |
def __cmp__(self, other): |
|
214 |
return cmp((self.start, self.length, self.ranges), |
|
215 |
(other.start, other.length, other.ranges)) |
|
216 |
||
217 |
||
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
218 |
class Transport(object): |
219 |
"""This class encapsulates methods for retrieving or putting a file
|
|
220 |
from/to a storage location.
|
|
221 |
||
222 |
Most functions have a _multi variant, which allows you to queue up
|
|
223 |
multiple requests. They generally have a dumb base implementation
|
|
224 |
which just iterates over the arguments, but smart Transport
|
|
225 |
implementations can do pipelining.
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
226 |
In general implementations should support having a generator or a list
|
227 |
as an argument (ie always iterate, never index)
|
|
1910.7.17
by Andrew Bennetts
Various cosmetic changes. |
228 |
|
229 |
: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. |
230 |
"""
|
231 |
||
1864.5.1
by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test. |
232 |
# implementations can override this if it is more efficient
|
233 |
# for them to combine larger read chunks together
|
|
1864.5.4
by John Arbash Meinel
play around with tuning the partial reads. |
234 |
_max_readv_combine = 50 |
1864.5.3
by John Arbash Meinel
Allow collapsing ranges even if they are just 'close' |
235 |
# It is better to read this much more data in order, rather
|
236 |
# than doing another seek. Even for the local filesystem,
|
|
237 |
# there is a benefit in just reading.
|
|
238 |
# TODO: jam 20060714 Do some real benchmarking to figure out
|
|
239 |
# where the biggest benefit between combining reads and
|
|
1864.5.8
by John Arbash Meinel
Cleanup and NEWS |
240 |
# and seeking is. Consider a runtime auto-tune.
|
1864.5.4
by John Arbash Meinel
play around with tuning the partial reads. |
241 |
_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. |
242 |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
243 |
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. |
244 |
super(Transport, self).__init__() |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
245 |
self.base = base |
246 |
||
1185.31.44
by John Arbash Meinel
Cleaned up Exceptions for all transports. |
247 |
def _translate_error(self, e, path, raise_generic=True): |
248 |
"""Translate an IOError or OSError into an appropriate bzr error.
|
|
249 |
||
250 |
This handles things like ENOENT, ENOTDIR, EEXIST, and EACCESS
|
|
251 |
"""
|
|
1963.2.6
by Robey Pointer
pychecker is on crack; go back to using 'is None'. |
252 |
if getattr(e, 'errno', None) is not None: |
1185.31.44
by John Arbash Meinel
Cleaned up Exceptions for all transports. |
253 |
if e.errno in (errno.ENOENT, errno.ENOTDIR): |
254 |
raise errors.NoSuchFile(path, extra=e) |
|
1185.31.58
by John Arbash Meinel
Updating for new transport tests so that they pass on win32 |
255 |
# I would rather use errno.EFOO, but there doesn't seem to be
|
256 |
# any matching for 267
|
|
257 |
# This is the error when doing a listdir on a file:
|
|
258 |
# WindowsError: [Errno 267] The directory name is invalid
|
|
259 |
if sys.platform == 'win32' and e.errno in (errno.ESRCH, 267): |
|
260 |
raise errors.NoSuchFile(path, extra=e) |
|
1185.31.44
by John Arbash Meinel
Cleaned up Exceptions for all transports. |
261 |
if e.errno == errno.EEXIST: |
262 |
raise errors.FileExists(path, extra=e) |
|
263 |
if e.errno == errno.EACCES: |
|
264 |
raise errors.PermissionDenied(path, extra=e) |
|
1553.5.10
by Martin Pool
New DirectoryNotEmpty exception, and raise this from local and memory |
265 |
if e.errno == errno.ENOTEMPTY: |
266 |
raise errors.DirectoryNotEmpty(path, extra=e) |
|
1558.10.1
by Aaron Bentley
Handle lockdirs over NFS properly |
267 |
if e.errno == errno.EBUSY: |
268 |
raise errors.ResourceBusy(path, extra=e) |
|
1185.31.44
by John Arbash Meinel
Cleaned up Exceptions for all transports. |
269 |
if raise_generic: |
270 |
raise errors.TransportError(orig_error=e) |
|
271 |
||
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
272 |
def clone(self, offset=None): |
273 |
"""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. |
274 |
using a subdirectory or parent directory. This allows connections
|
275 |
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. |
276 |
"""
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
277 |
raise NotImplementedError(self.clone) |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
278 |
|
2475.3.2
by John Arbash Meinel
Add Transport.ensure_base() |
279 |
def ensure_base(self): |
280 |
"""Ensure that the directory this transport references exists.
|
|
281 |
||
282 |
This will create a directory if it doesn't exist.
|
|
283 |
:return: True if the directory was created, False otherwise.
|
|
284 |
"""
|
|
285 |
# The default implementation just uses "Easier to ask for forgiveness
|
|
286 |
# than permission". We attempt to create the directory, and just
|
|
287 |
# suppress a FileExists exception.
|
|
288 |
try: |
|
289 |
self.mkdir('.') |
|
290 |
except errors.FileExists: |
|
291 |
return False |
|
292 |
else: |
|
293 |
return True |
|
294 |
||
907.1.32
by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate. |
295 |
def should_cache(self): |
296 |
"""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. |
297 |
"""
|
907.1.32
by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate. |
298 |
return False |
907.1.22
by John Arbash Meinel
Fixed some encoding issues, added is_remote function for Transport objects. |
299 |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
300 |
def _pump(self, from_file, to_file): |
301 |
"""Most children will need to copy from one file-like
|
|
302 |
object or string to another one.
|
|
303 |
This just gives them something easy to call.
|
|
304 |
"""
|
|
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 |
305 |
assert not isinstance(from_file, basestring), \ |
306 |
'_pump should only be called on files not %s' % (type(from_file,)) |
|
1996.3.6
by John Arbash Meinel
Find a few places that weren't importing their dependencies. |
307 |
osutils.pumpfile(from_file, to_file) |
1948.3.8
by Vincent LADEUIL
_pump accepts strings finally :) |
308 |
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
309 |
def _get_total(self, multi): |
310 |
"""Try to figure out how many entries are in multi,
|
|
311 |
but if not possible, return None.
|
|
312 |
"""
|
|
313 |
try: |
|
314 |
return len(multi) |
|
315 |
except TypeError: # We can't tell how many, because relpaths is a generator |
|
316 |
return None |
|
317 |
||
318 |
def _update_pb(self, pb, msg, count, total): |
|
319 |
"""Update the progress bar based on the current count
|
|
320 |
and total available, total may be None if it was
|
|
321 |
not possible to determine.
|
|
322 |
"""
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
323 |
if pb is None: |
324 |
return
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
325 |
if total is None: |
326 |
pb.update(msg, count, count+1) |
|
327 |
else: |
|
328 |
pb.update(msg, count, total) |
|
329 |
||
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
330 |
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. |
331 |
"""Iterate over all entries in multi, passing them to func,
|
332 |
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. |
333 |
|
334 |
:param expand: If True, the entries will be passed to the function
|
|
335 |
by expanding the tuple. If False, it will be passed
|
|
336 |
as a single parameter.
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
337 |
"""
|
338 |
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. |
339 |
result = [] |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
340 |
count = 0 |
341 |
for entry in multi: |
|
342 |
self._update_pb(pb, msg, count, total) |
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
343 |
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. |
344 |
result.append(func(*entry)) |
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
345 |
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. |
346 |
result.append(func(entry)) |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
347 |
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. |
348 |
return tuple(result) |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
349 |
|
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
350 |
def abspath(self, relpath): |
351 |
"""Return the full url to the given relative path.
|
|
1910.16.6
by Andrew Bennetts
Update Transport.abspath docstring. |
352 |
|
353 |
: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. |
354 |
"""
|
1442.1.44
by Robert Collins
Many transport related tweaks: |
355 |
|
1910.16.2
by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport. |
356 |
# XXX: Robert Collins 20051016 - is this really needed in the public
|
357 |
# interface ?
|
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
358 |
raise NotImplementedError(self.abspath) |
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
359 |
|
1910.16.2
by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport. |
360 |
def _combine_paths(self, base_path, relpath): |
361 |
"""Transform a Transport-relative path to a remote absolute path.
|
|
362 |
||
363 |
This does not handle substitution of ~ but does handle '..' and '.'
|
|
364 |
components.
|
|
365 |
||
366 |
Examples::
|
|
367 |
||
1996.3.20
by John Arbash Meinel
[merge] bzr.dev 2063 |
368 |
t._combine_paths('/home/sarah', 'project/foo')
|
369 |
=> '/home/sarah/project/foo'
|
|
370 |
t._combine_paths('/home/sarah', '../../etc')
|
|
371 |
=> '/etc'
|
|
2070.3.2
by Andrew Bennetts
Merge from bzr.dev |
372 |
t._combine_paths('/home/sarah', '/etc')
|
373 |
=> '/etc'
|
|
1910.16.2
by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport. |
374 |
|
375 |
:param base_path: urlencoded path for the transport root; typically a
|
|
376 |
URL but need not contain scheme/host/etc.
|
|
377 |
:param relpath: relative url string for relative part of remote path.
|
|
378 |
:return: urlencoded string for final path.
|
|
379 |
"""
|
|
380 |
# FIXME: share the common code across more transports; variants of
|
|
381 |
# this likely occur in http and sftp too.
|
|
382 |
#
|
|
383 |
# TODO: Also need to consider handling of ~, which might vary between
|
|
384 |
# transports?
|
|
385 |
if not isinstance(relpath, str): |
|
386 |
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 |
387 |
if relpath.startswith('/'): |
388 |
base_parts = [] |
|
389 |
else: |
|
390 |
base_parts = base_path.split('/') |
|
1910.16.2
by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport. |
391 |
if len(base_parts) > 0 and base_parts[-1] == '': |
392 |
base_parts = base_parts[:-1] |
|
393 |
for p in relpath.split('/'): |
|
394 |
if p == '..': |
|
395 |
if len(base_parts) == 0: |
|
396 |
# In most filesystems, a request for the parent
|
|
397 |
# of root, just returns root.
|
|
398 |
continue
|
|
399 |
base_parts.pop() |
|
400 |
elif p == '.': |
|
401 |
continue # No-op |
|
402 |
elif p != '': |
|
403 |
base_parts.append(p) |
|
404 |
path = '/'.join(base_parts) |
|
2070.3.1
by Andrew Bennetts
Fix memory_transport.abspath('/foo') |
405 |
if not path.startswith('/'): |
406 |
path = '/' + path |
|
1910.16.2
by Andrew Bennetts
Reduce transport code duplication by creating a '_combine_paths' method to Transport. |
407 |
return path |
408 |
||
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
409 |
def relpath(self, abspath): |
410 |
"""Return the local path portion from a given absolute path.
|
|
1442.1.44
by Robert Collins
Many transport related tweaks: |
411 |
|
412 |
This default implementation is not suitable for filesystems with
|
|
413 |
aliasing, such as that given by symlinks, where a path may not
|
|
414 |
start with our base, but still be a relpath once aliasing is
|
|
415 |
resolved.
|
|
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
416 |
"""
|
1185.31.44
by John Arbash Meinel
Cleaned up Exceptions for all transports. |
417 |
# TODO: This might want to use bzrlib.osutils.relpath
|
418 |
# but we have to watch out because of the prefix issues
|
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
419 |
if not (abspath == self.base[:-1] or abspath.startswith(self.base)): |
1185.31.44
by John Arbash Meinel
Cleaned up Exceptions for all transports. |
420 |
raise errors.PathNotChild(abspath, self.base) |
1442.1.44
by Robert Collins
Many transport related tweaks: |
421 |
pl = len(self.base) |
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
422 |
return abspath[pl:].strip('/') |
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
423 |
|
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 |
424 |
def local_abspath(self, relpath): |
425 |
"""Return the absolute path on the local filesystem.
|
|
426 |
||
427 |
This function will only be defined for Transports which have a
|
|
428 |
physical local filesystem representation.
|
|
429 |
"""
|
|
2018.18.4
by Martin Pool
Change Transport.local_abspath to raise NotLocalUrl, and test. |
430 |
raise errors.NotLocalUrl(self.abspath(relpath)) |
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 |
431 |
|
432 |
||
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
433 |
def has(self, relpath): |
1442.1.44
by Robert Collins
Many transport related tweaks: |
434 |
"""Does the file relpath exist?
|
435 |
|
|
436 |
Note that some transports MAY allow querying on directories, but this
|
|
1553.5.66
by Martin Pool
doc |
437 |
is not part of the protocol. In other words, the results of
|
1786.1.8
by John Arbash Meinel
[merge] Johan Rydberg test updates |
438 |
t.has("a_directory_name") are undefined.
|
1910.7.17
by Andrew Bennetts
Various cosmetic changes. |
439 |
|
440 |
:rtype: bool
|
|
1442.1.44
by Robert Collins
Many transport related tweaks: |
441 |
"""
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
442 |
raise NotImplementedError(self.has) |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
443 |
|
907.1.36
by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class. |
444 |
def has_multi(self, relpaths, pb=None): |
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
445 |
"""Return True/False for each entry in relpaths"""
|
446 |
total = self._get_total(relpaths) |
|
447 |
count = 0 |
|
448 |
for relpath in relpaths: |
|
907.1.36
by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class. |
449 |
self._update_pb(pb, 'has', count, total) |
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
450 |
yield self.has(relpath) |
451 |
count += 1 |
|
452 |
||
1185.16.155
by John Arbash Meinel
Added a has_any function to the Transport API |
453 |
def has_any(self, relpaths): |
454 |
"""Return True if any of the paths exist."""
|
|
455 |
for relpath in relpaths: |
|
456 |
if self.has(relpath): |
|
457 |
return True |
|
458 |
return False |
|
459 |
||
1442.1.44
by Robert Collins
Many transport related tweaks: |
460 |
def iter_files_recursive(self): |
461 |
"""Iter the relative paths of files in the transports sub-tree.
|
|
1553.5.13
by Martin Pool
New Transport.rename that mustn't overwrite |
462 |
|
463 |
*NOTE*: This only lists *files*, not subdirectories!
|
|
1442.1.44
by Robert Collins
Many transport related tweaks: |
464 |
|
465 |
As with other listing functions, only some transports implement this,.
|
|
466 |
you may check via is_listable to determine if it will.
|
|
467 |
"""
|
|
1530.1.4
by Robert Collins
integrate Memory tests into transport interface tests. |
468 |
raise errors.TransportNotPossible("This transport has not " |
1530.1.21
by Robert Collins
Review feedback fixes. |
469 |
"implemented iter_files_recursive "
|
1530.1.4
by Robert Collins
integrate Memory tests into transport interface tests. |
470 |
"(but must claim to be listable "
|
471 |
"to trigger this error).") |
|
1442.1.44
by Robert Collins
Many transport related tweaks: |
472 |
|
2164.2.15
by Vincent Ladeuil
Http redirections are not followed by default. Do not use hints |
473 |
def get(self, relpath): |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
474 |
"""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 |
475 |
|
476 |
: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 |
477 |
:rtype: File-like object.
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
478 |
"""
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
479 |
raise NotImplementedError(self.get) |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
480 |
|
1955.3.3
by John Arbash Meinel
Implement and test 'get_bytes' |
481 |
def get_bytes(self, relpath): |
482 |
"""Get a raw string of the bytes for a file at the given location.
|
|
483 |
||
484 |
:param relpath: The relative path to the file
|
|
485 |
"""
|
|
486 |
return self.get(relpath).read() |
|
487 |
||
1910.19.2
by Andrew Bennetts
Add a new method ``Transport.get_smart_client()``. This is provided to allow |
488 |
def get_smart_client(self): |
489 |
"""Return a smart client for this transport if possible.
|
|
490 |
||
2018.2.3
by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol. |
491 |
A smart client doesn't imply the presence of a smart server: it implies
|
492 |
that the smart protocol can be tunnelled via this transport.
|
|
493 |
||
1910.19.2
by Andrew Bennetts
Add a new method ``Transport.get_smart_client()``. This is provided to allow |
494 |
:raises NoSmartServer: if no smart server client is available.
|
495 |
"""
|
|
496 |
raise errors.NoSmartServer(self.base) |
|
497 |
||
2018.2.3
by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol. |
498 |
def get_smart_medium(self): |
499 |
"""Return a smart client medium for this transport if possible.
|
|
500 |
||
501 |
A smart medium doesn't imply the presence of a smart server: it implies
|
|
502 |
that the smart protocol can be tunnelled via this transport.
|
|
503 |
||
504 |
:raises NoSmartMedium: if no smart server medium is available.
|
|
505 |
"""
|
|
506 |
raise errors.NoSmartMedium(self) |
|
507 |
||
1594.2.5
by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support. |
508 |
def readv(self, relpath, offsets): |
509 |
"""Get parts of the file at the given relative path.
|
|
510 |
||
511 |
:offsets: A list of (offset, size) tuples.
|
|
512 |
:return: A list or generator of (offset, data) tuples
|
|
513 |
"""
|
|
1864.5.1
by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test. |
514 |
if not offsets: |
1594.2.16
by Robert Collins
Coalesce readv requests on file based transports. |
515 |
return
|
1864.5.1
by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test. |
516 |
|
1864.5.7
by John Arbash Meinel
remove disable prefetch support |
517 |
fp = self.get(relpath) |
2001.3.2
by John Arbash Meinel
Force all transports to raise ShortReadvError if they can |
518 |
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. |
519 |
|
2001.3.2
by John Arbash Meinel
Force all transports to raise ShortReadvError if they can |
520 |
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. |
521 |
"""An implementation of readv that uses fp.seek and fp.read.
|
522 |
||
523 |
This uses _coalesce_offsets to issue larger reads and fewer seeks.
|
|
524 |
||
525 |
:param fp: A file-like object that supports seek() and read(size)
|
|
526 |
:param offsets: A list of offsets to be read from the given file.
|
|
527 |
:return: yield (pos, data) tuples for each request
|
|
528 |
"""
|
|
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 |
529 |
# We are going to iterate multiple times, we need a list
|
530 |
offsets = list(offsets) |
|
531 |
sorted_offsets = sorted(offsets) |
|
532 |
||
533 |
# 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. |
534 |
offset_stack = iter(offsets) |
535 |
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 |
536 |
coalesced = self._coalesce_offsets(sorted_offsets, |
1864.5.3
by John Arbash Meinel
Allow collapsing ranges even if they are just 'close' |
537 |
limit=self._max_readv_combine, |
538 |
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 |
539 |
|
540 |
# Cache the results, but only until they have been fulfilled
|
|
541 |
data_map = {} |
|
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
542 |
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. |
543 |
# TODO: jam 20060724 it might be faster to not issue seek if
|
544 |
# we are already at the right location. This should be
|
|
545 |
# benchmarked.
|
|
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
546 |
fp.seek(c_offset.start) |
547 |
data = fp.read(c_offset.length) |
|
2001.3.2
by John Arbash Meinel
Force all transports to raise ShortReadvError if they can |
548 |
if len(data) < c_offset.length: |
549 |
raise errors.ShortReadvError(relpath, c_offset.start, |
|
2001.3.3
by John Arbash Meinel
review feedback: add the actual count written to ShortReadvError |
550 |
c_offset.length, actual=len(data)) |
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
551 |
for suboffset, subsize in c_offset.ranges: |
552 |
key = (c_offset.start+suboffset, subsize) |
|
553 |
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. |
554 |
|
1864.5.8
by John Arbash Meinel
Cleanup and NEWS |
555 |
# 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. |
556 |
while cur_offset_and_size in data_map: |
557 |
this_data = data_map.pop(cur_offset_and_size) |
|
558 |
yield cur_offset_and_size[0], this_data |
|
559 |
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. |
560 |
|
561 |
@staticmethod
|
|
1864.5.3
by John Arbash Meinel
Allow collapsing ranges even if they are just 'close' |
562 |
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. |
563 |
"""Yield coalesced offsets.
|
564 |
||
565 |
With a long list of neighboring requests, combine them
|
|
566 |
into a single large request, while retaining the original
|
|
567 |
offsets.
|
|
568 |
Turns [(15, 10), (25, 10)] => [(15, 20, [(0, 10), (10, 10)])]
|
|
569 |
||
570 |
:param offsets: A list of (start, length) pairs
|
|
571 |
:param limit: Only combine a maximum of this many pairs
|
|
572 |
Some transports penalize multiple reads more than
|
|
573 |
others, and sometimes it is better to return early.
|
|
574 |
0 means no limit
|
|
1864.5.3
by John Arbash Meinel
Allow collapsing ranges even if they are just 'close' |
575 |
:param fudge_factor: All transports have some level of 'it is
|
576 |
better to read some more data and throw it away rather
|
|
577 |
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. |
578 |
:return: yield _CoalescedOffset objects, which have members for wher
|
579 |
to start, how much to read, and how to split those
|
|
580 |
chunks back up
|
|
1864.5.1
by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test. |
581 |
"""
|
582 |
last_end = None |
|
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
583 |
cur = _CoalescedOffset(None, None, []) |
1864.5.1
by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test. |
584 |
|
585 |
for start, size in offsets: |
|
586 |
end = start + size |
|
587 |
if (last_end is not None |
|
1864.5.3
by John Arbash Meinel
Allow collapsing ranges even if they are just 'close' |
588 |
and start <= last_end + fudge_factor |
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
589 |
and start >= cur.start |
590 |
and (limit <= 0 or len(cur.ranges) < limit)): |
|
591 |
cur.length = end - cur.start |
|
592 |
cur.ranges.append((start-cur.start, size)) |
|
1594.2.16
by Robert Collins
Coalesce readv requests on file based transports. |
593 |
else: |
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
594 |
if cur.start is not None: |
595 |
yield cur |
|
596 |
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. |
597 |
last_end = end |
598 |
||
1864.5.9
by John Arbash Meinel
Switch to returning an object to make the api more understandable. |
599 |
if cur.start is not None: |
600 |
yield cur |
|
1864.5.1
by John Arbash Meinel
Change the readv combining algorithm for one that is easier to test. |
601 |
|
602 |
return
|
|
1594.2.5
by Robert Collins
Readv patch from Johan Rydberg giving knits partial download support. |
603 |
|
907.1.50
by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown. |
604 |
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. |
605 |
"""Get a list of file-like objects, one for each entry in relpaths.
|
606 |
||
607 |
: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. |
608 |
:param pb: An optional ProgressBar for indicating percent done.
|
609 |
: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. |
610 |
"""
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
611 |
# TODO: Consider having this actually buffer the requests,
|
612 |
# in the default mode, it probably won't give worse performance,
|
|
613 |
# and all children wouldn't have to implement buffering
|
|
907.1.16
by John Arbash Meinel
Fixing a few cut&paste typos. |
614 |
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. |
615 |
count = 0 |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
616 |
for relpath in relpaths: |
907.1.16
by John Arbash Meinel
Fixing a few cut&paste typos. |
617 |
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. |
618 |
yield self.get(relpath) |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
619 |
count += 1 |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
620 |
|
1955.3.6
by John Arbash Meinel
Lots of deprecation warnings, but no errors |
621 |
@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. |
622 |
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' |
623 |
"""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 |
624 |
|
625 |
: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' |
626 |
: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. |
627 |
:param mode: The mode for the newly created file,
|
628 |
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. |
629 |
"""
|
1955.3.6
by John Arbash Meinel
Lots of deprecation warnings, but no errors |
630 |
if isinstance(f, str): |
631 |
return self.put_bytes(relpath, f, mode=mode) |
|
632 |
else: |
|
633 |
return self.put_file(relpath, f, mode=mode) |
|
634 |
||
1955.3.27
by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions |
635 |
def put_bytes(self, relpath, bytes, mode=None): |
636 |
"""Atomically put the supplied bytes into the given location.
|
|
637 |
||
638 |
:param relpath: The location to put the contents, relative to the
|
|
639 |
transport base.
|
|
640 |
:param bytes: A bytestring of data.
|
|
641 |
:param mode: Create the file with the given mode.
|
|
642 |
:return: None
|
|
643 |
"""
|
|
2414.1.3
by Andrew Bennetts
Fix test failures under 'python2.4 -O' ('python2.5 -O' was already passing). |
644 |
if not isinstance(bytes, str): |
645 |
raise AssertionError( |
|
646 |
'bytes must be a plain string, not %s' % type(bytes)) |
|
1955.3.27
by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions |
647 |
return self.put_file(relpath, StringIO(bytes), mode=mode) |
648 |
||
649 |
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 |
650 |
create_parent_dir=False, |
651 |
dir_mode=None): |
|
1955.3.27
by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions |
652 |
"""Copy the string into the target location.
|
653 |
||
654 |
This function is not strictly safe to use. See
|
|
655 |
Transport.put_bytes_non_atomic for more information.
|
|
656 |
||
657 |
:param relpath: The remote location to put the contents.
|
|
658 |
:param bytes: A string object containing the raw bytes to write into
|
|
659 |
the target file.
|
|
660 |
:param mode: Possible access permissions for new file.
|
|
661 |
None means do not set remote permissions.
|
|
662 |
:param create_parent_dir: If we cannot create the target file because
|
|
663 |
the parent directory does not exist, go ahead and
|
|
664 |
create it, and then try again.
|
|
1946.2.12
by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put |
665 |
: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 |
666 |
"""
|
2414.1.3
by Andrew Bennetts
Fix test failures under 'python2.4 -O' ('python2.5 -O' was already passing). |
667 |
if not isinstance(bytes, str): |
668 |
raise AssertionError( |
|
669 |
'bytes must be a plain string, not %s' % type(bytes)) |
|
1955.3.27
by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions |
670 |
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 |
671 |
create_parent_dir=create_parent_dir, |
672 |
dir_mode=dir_mode) |
|
1955.3.27
by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions |
673 |
|
1955.3.6
by John Arbash Meinel
Lots of deprecation warnings, but no errors |
674 |
def put_file(self, relpath, f, mode=None): |
675 |
"""Copy the file-like object into the location.
|
|
676 |
||
677 |
:param relpath: Location to put the contents, relative to base.
|
|
678 |
:param f: File-like object.
|
|
679 |
:param mode: The mode for the newly created file,
|
|
680 |
None means just use the default.
|
|
681 |
"""
|
|
682 |
# We would like to mark this as NotImplemented, but most likely
|
|
683 |
# transports have defined it in terms of the old api.
|
|
684 |
symbol_versioning.warn('Transport %s should implement put_file,' |
|
685 |
' rather than implementing put() as of'
|
|
686 |
' version 0.11.'
|
|
687 |
% (self.__class__.__name__,), |
|
688 |
DeprecationWarning) |
|
689 |
return self.put(relpath, f, mode=mode) |
|
690 |
#raise NotImplementedError(self.put_file)
|
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
691 |
|
1955.3.27
by John Arbash Meinel
rename non_atomic_put_* to put_*non_atomic, and re-order the functions |
692 |
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 |
693 |
create_parent_dir=False, |
694 |
dir_mode=None): |
|
1946.1.1
by John Arbash Meinel
Stub out the test and basic implementation for 'non_atomic_put' |
695 |
"""Copy the file-like object into the target location.
|
696 |
||
697 |
This function is not strictly safe to use. It is only meant to
|
|
698 |
be used when you already know that the target does not exist.
|
|
699 |
It is not safe, because it will open and truncate the remote
|
|
700 |
file. So there may be a time when the file has invalid contents.
|
|
701 |
||
702 |
:param relpath: The remote location to put the contents.
|
|
703 |
:param f: File-like object.
|
|
704 |
:param mode: Possible access permissions for new file.
|
|
705 |
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 |
706 |
:param create_parent_dir: If we cannot create the target file because
|
707 |
the parent directory does not exist, go ahead and
|
|
708 |
create it, and then try again.
|
|
1946.2.12
by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put |
709 |
: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' |
710 |
"""
|
711 |
# 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 |
712 |
try: |
1955.3.19
by John Arbash Meinel
rename non_atomic_put => non_atomic_put_file |
713 |
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 |
714 |
except errors.NoSuchFile: |
715 |
if not create_parent_dir: |
|
716 |
raise
|
|
717 |
parent_dir = osutils.dirname(relpath) |
|
718 |
if parent_dir: |
|
1946.2.12
by John Arbash Meinel
Add ability to pass a directory mode to non_atomic_put |
719 |
self.mkdir(parent_dir, mode=dir_mode) |
1955.3.19
by John Arbash Meinel
rename non_atomic_put => non_atomic_put_file |
720 |
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' |
721 |
|
1955.3.7
by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves |
722 |
@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. |
723 |
def put_multi(self, files, mode=None, pb=None): |
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
724 |
"""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. |
725 |
|
726 |
: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. |
727 |
: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. |
728 |
: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. |
729 |
:return: The number of files copied.
|
730 |
"""
|
|
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 |
731 |
def _put(path, f): |
1955.3.7
by John Arbash Meinel
Fix the deprecation warnings in the transport tests themselves |
732 |
if isinstance(f, str): |
733 |
self.put_bytes(path, f, mode=mode) |
|
734 |
else: |
|
735 |
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 |
736 |
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. |
737 |
|
1185.58.2
by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work. |
738 |
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. |
739 |
"""Create a directory at the given path."""
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
740 |
raise NotImplementedError(self.mkdir) |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
741 |
|
1185.58.2
by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work. |
742 |
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 |
743 |
"""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. |
744 |
def mkdir(path): |
745 |
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. |
746 |
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 |
747 |
|
1955.3.15
by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes |
748 |
@deprecated_method(zero_eleven) |
1752.2.31
by Martin Pool
[broken] some support for write operations over hpss |
749 |
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 |
750 |
"""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. |
751 |
|
1955.3.2
by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append |
752 |
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. |
753 |
|
754 |
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. |
755 |
"""
|
1955.3.15
by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes |
756 |
return self.append_file(relpath, f, mode=mode) |
757 |
||
758 |
def append_file(self, relpath, f, mode=None): |
|
1910.7.18
by Andrew Bennetts
Merge from bzr.dev |
759 |
"""Append bytes from a file-like object to a file at relpath.
|
760 |
||
761 |
The file is created if it does not already exist.
|
|
762 |
||
763 |
:param f: a file-like object of the bytes to append.
|
|
764 |
:param mode: Unix mode for newly created files. This is not used for
|
|
765 |
existing files.
|
|
766 |
||
767 |
: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 |
768 |
"""
|
769 |
symbol_versioning.warn('Transport %s should implement append_file,' |
|
770 |
' rather than implementing append() as of'
|
|
771 |
' version 0.11.'
|
|
772 |
% (self.__class__.__name__,), |
|
773 |
DeprecationWarning) |
|
774 |
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. |
775 |
|
1955.3.2
by John Arbash Meinel
Implement and test 'Transport.append_bytes', cleanup the tests of plain append |
776 |
def append_bytes(self, relpath, bytes, mode=None): |
1910.7.18
by Andrew Bennetts
Merge from bzr.dev |
777 |
"""Append bytes to a file at relpath.
|
778 |
||
779 |
The file is created if it does not already exist.
|
|
780 |
||
781 |
:type f: str
|
|
782 |
:param f: a string of the bytes to append.
|
|
783 |
:param mode: Unix mode for newly created files. This is not used for
|
|
784 |
existing files.
|
|
785 |
||
786 |
: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 |
787 |
"""
|
788 |
assert isinstance(bytes, str), \ |
|
789 |
'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 |
790 |
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 |
791 |
|
1185.11.19
by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings. |
792 |
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. |
793 |
"""Append the text in each file-like or string object to
|
794 |
the supplied location.
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
795 |
|
796 |
:param files: A set of (path, f) entries
|
|
797 |
: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. |
798 |
"""
|
1955.3.15
by John Arbash Meinel
Deprecate 'Transport.append' in favor of Transport.append_file or Transport.append_bytes |
799 |
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. |
800 |
|
801 |
def copy(self, rel_from, rel_to): |
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
802 |
"""Copy the item at rel_from to the location at rel_to.
|
803 |
|
|
804 |
Override this for efficiency if a specific transport can do it
|
|
805 |
faster than this default implementation.
|
|
806 |
"""
|
|
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 |
807 |
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. |
808 |
|
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
809 |
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. |
810 |
"""Copy a bunch of entries.
|
811 |
|
|
812 |
:param relpaths: A list of tuples of the form [(from, to), (from, to),...]
|
|
813 |
"""
|
|
814 |
# This is the non-pipelined implementation, so that
|
|
815 |
# implementors don't have to implement everything.
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
816 |
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. |
817 |
|
1185.58.2
by John Arbash Meinel
Added mode to the appropriate transport functions, and tests to make sure they work. |
818 |
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. |
819 |
"""Copy a set of entries from self into another Transport.
|
820 |
||
821 |
: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. |
822 |
: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 |
823 |
TODO: This interface needs to be updated so that the target location
|
824 |
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. |
825 |
"""
|
826 |
# The dummy implementation just does a simple get + put
|
|
827 |
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 |
828 |
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. |
829 |
|
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. |
830 |
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. |
831 |
|
1534.4.26
by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create. |
832 |
def copy_tree(self, from_relpath, to_relpath): |
833 |
"""Copy a subtree from one relpath to another.
|
|
834 |
||
835 |
If a faster implementation is available, specific transports should
|
|
836 |
implement it.
|
|
837 |
"""
|
|
838 |
source = self.clone(from_relpath) |
|
839 |
self.mkdir(to_relpath) |
|
840 |
target = self.clone(to_relpath) |
|
841 |
files = [] |
|
842 |
directories = ['.'] |
|
843 |
while directories: |
|
844 |
dir = directories.pop() |
|
845 |
if dir != '.': |
|
846 |
target.mkdir(dir) |
|
847 |
for path in source.list_dir(dir): |
|
848 |
path = dir + '/' + path |
|
849 |
stat = source.stat(path) |
|
850 |
if S_ISDIR(stat.st_mode): |
|
851 |
directories.append(path) |
|
852 |
else: |
|
853 |
files.append(path) |
|
854 |
source.copy_to(files, target) |
|
855 |
||
1553.5.13
by Martin Pool
New Transport.rename that mustn't overwrite |
856 |
def rename(self, rel_from, rel_to): |
857 |
"""Rename a file or directory.
|
|
858 |
||
859 |
This *must* fail if the destination is a nonempty directory - it must
|
|
860 |
not automatically remove it. It should raise DirectoryNotEmpty, or
|
|
861 |
some other PathError if the case can't be specifically detected.
|
|
862 |
||
863 |
If the destination is an empty directory or a file this function may
|
|
864 |
either fail or succeed, depending on the underlying transport. It
|
|
865 |
should not attempt to remove the destination if overwriting is not the
|
|
866 |
native transport behaviour. If at all possible the transport should
|
|
867 |
ensure that the rename either completes or not, without leaving the
|
|
868 |
destination deleted and the new file not moved in place.
|
|
869 |
||
870 |
This is intended mainly for use in implementing LockDir.
|
|
871 |
"""
|
|
872 |
# transports may need to override this
|
|
1553.5.17
by Martin Pool
Transport.rename should be unimplemented in base class |
873 |
raise NotImplementedError(self.rename) |
1553.5.13
by Martin Pool
New Transport.rename that mustn't overwrite |
874 |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
875 |
def move(self, rel_from, rel_to): |
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
876 |
"""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 |
877 |
|
878 |
The destination is deleted if possible, even if it's a non-empty
|
|
879 |
directory tree.
|
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
880 |
|
881 |
If a transport can directly implement this it is suggested that
|
|
882 |
it do so for efficiency.
|
|
883 |
"""
|
|
1534.4.26
by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create. |
884 |
if S_ISDIR(self.stat(rel_from).st_mode): |
885 |
self.copy_tree(rel_from, rel_to) |
|
886 |
self.delete_tree(rel_from) |
|
887 |
else: |
|
888 |
self.copy(rel_from, rel_to) |
|
889 |
self.delete(rel_from) |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
890 |
|
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
891 |
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. |
892 |
"""Move a bunch of entries.
|
893 |
|
|
894 |
:param relpaths: A list of tuples of the form [(from1, to1), (from2, to2),...]
|
|
895 |
"""
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
896 |
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. |
897 |
|
898 |
def move_multi_to(self, relpaths, rel_to): |
|
899 |
"""Move a bunch of entries to a single location.
|
|
900 |
This differs from move_multi in that you give a list of from, and
|
|
901 |
a single destination, rather than multiple destinations.
|
|
902 |
||
903 |
:param relpaths: A list of relative paths [from1, from2, from3, ...]
|
|
904 |
:param rel_to: A directory where each entry should be placed.
|
|
905 |
"""
|
|
906 |
# This is not implemented, because you need to do special tricks to
|
|
907 |
# 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. |
908 |
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. |
909 |
|
910 |
def delete(self, relpath): |
|
911 |
"""Delete the item at relpath"""
|
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
912 |
raise NotImplementedError(self.delete) |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
913 |
|
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
914 |
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. |
915 |
"""Queue up a bunch of deletes to be done.
|
916 |
"""
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
917 |
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. |
918 |
|
1534.4.15
by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports. |
919 |
def delete_tree(self, relpath): |
920 |
"""Delete an entire tree. This may require a listable transport."""
|
|
921 |
subtree = self.clone(relpath) |
|
922 |
files = [] |
|
923 |
directories = ['.'] |
|
924 |
pending_rmdirs = [] |
|
925 |
while directories: |
|
926 |
dir = directories.pop() |
|
927 |
if dir != '.': |
|
928 |
pending_rmdirs.append(dir) |
|
929 |
for path in subtree.list_dir(dir): |
|
930 |
path = dir + '/' + path |
|
931 |
stat = subtree.stat(path) |
|
932 |
if S_ISDIR(stat.st_mode): |
|
933 |
directories.append(path) |
|
934 |
else: |
|
935 |
files.append(path) |
|
936 |
subtree.delete_multi(files) |
|
937 |
pending_rmdirs.reverse() |
|
938 |
for dir in pending_rmdirs: |
|
939 |
subtree.rmdir(dir) |
|
940 |
self.rmdir(relpath) |
|
941 |
||
1534.5.7
by Robert Collins
Start factoring out the upgrade policy logic. |
942 |
def __repr__(self): |
943 |
return "<%s.%s url=%s>" % (self.__module__, self.__class__.__name__, self.base) |
|
944 |
||
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
945 |
def stat(self, relpath): |
946 |
"""Return the stat information for a file.
|
|
947 |
WARNING: This may not be implementable for all protocols, so use
|
|
948 |
sparingly.
|
|
1442.1.44
by Robert Collins
Many transport related tweaks: |
949 |
NOTE: This returns an object with fields such as 'st_size'. It MAY
|
950 |
or MAY NOT return the literal result of an os.stat() call, so all
|
|
951 |
access should be via named fields.
|
|
952 |
ALSO NOTE: Stats of directories may not be supported on some
|
|
953 |
transports.
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
954 |
"""
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
955 |
raise NotImplementedError(self.stat) |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
956 |
|
1534.4.15
by Robert Collins
Remove shutil dependency in upgrade - create a delete_tree method for transports. |
957 |
def rmdir(self, relpath): |
958 |
"""Remove a directory at the given path."""
|
|
959 |
raise NotImplementedError |
|
960 |
||
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
961 |
def stat_multi(self, relpaths, pb=None): |
962 |
"""Stat multiple files and return the information.
|
|
963 |
"""
|
|
964 |
#TODO: Is it worth making this a generator instead of a
|
|
965 |
# returning a list?
|
|
966 |
stats = [] |
|
967 |
def gather(path): |
|
968 |
stats.append(self.stat(path)) |
|
969 |
||
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
970 |
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. |
971 |
return stats |
972 |
||
1400.1.1
by Robert Collins
implement a basic test for the ui branch command from http servers |
973 |
def listable(self): |
974 |
"""Return True if this store supports listing."""
|
|
1540.3.1
by Martin Pool
First-cut implementation of pycurl. Substantially faster than using urllib. |
975 |
raise NotImplementedError(self.listable) |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
976 |
|
977 |
def list_dir(self, relpath): |
|
978 |
"""Return a list of all files at the given location.
|
|
979 |
WARNING: many transports do not support this, so trying avoid using
|
|
980 |
it if at all possible.
|
|
981 |
"""
|
|
1910.16.1
by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible. |
982 |
raise errors.TransportNotPossible("Transport %r has not " |
1530.1.21
by Robert Collins
Review feedback fixes. |
983 |
"implemented list_dir "
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
984 |
"(but must claim to be listable "
|
1910.16.1
by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible. |
985 |
"to trigger this error)."
|
986 |
% (self)) |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
987 |
|
907.1.24
by John Arbash Meinel
Remote functionality work. |
988 |
def lock_read(self, relpath): |
989 |
"""Lock the given file for shared (read) access.
|
|
1910.16.1
by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible. |
990 |
|
991 |
WARNING: many transports do not support this, so trying avoid using it.
|
|
992 |
These methods may be removed in the future.
|
|
993 |
||
994 |
Transports may raise TransportNotPossible if OS-level locks cannot be
|
|
995 |
taken over this transport.
|
|
907.1.24
by John Arbash Meinel
Remote functionality work. |
996 |
|
997 |
:return: A lock object, which should contain an unlock() function.
|
|
998 |
"""
|
|
1910.16.1
by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible. |
999 |
raise errors.TransportNotPossible("transport locks not supported on %s" % self) |
907.1.24
by John Arbash Meinel
Remote functionality work. |
1000 |
|
1001 |
def lock_write(self, relpath): |
|
1002 |
"""Lock the given file for exclusive (write) access.
|
|
1910.16.1
by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible. |
1003 |
|
1004 |
WARNING: many transports do not support this, so trying avoid using it.
|
|
1005 |
These methods may be removed in the future.
|
|
1006 |
||
1007 |
Transports may raise TransportNotPossible if OS-level locks cannot be
|
|
1008 |
taken over this transport.
|
|
907.1.24
by John Arbash Meinel
Remote functionality work. |
1009 |
|
1010 |
:return: A lock object, which should contain an unlock() function.
|
|
1011 |
"""
|
|
1910.16.1
by Andrew Bennetts
lock_read and lock_write may raise TransportNotPossible. |
1012 |
raise errors.TransportNotPossible("transport locks not supported on %s" % self) |
907.1.24
by John Arbash Meinel
Remote functionality work. |
1013 |
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1014 |
def is_readonly(self): |
1015 |
"""Return true if this connection cannot be written to."""
|
|
1016 |
return False |
|
1017 |
||
1608.2.7
by Martin Pool
Rename supports_unix_modebits to _can_roundtrip_unix_modebits for clarity |
1018 |
def _can_roundtrip_unix_modebits(self): |
1608.2.5
by Martin Pool
Add Transport.supports_unix_modebits, so tests can |
1019 |
"""Return true if this transport can store and retrieve unix modebits.
|
1020 |
||
1021 |
(For example, 0700 to make a directory owner-private.)
|
|
1022 |
|
|
1023 |
Note: most callers will not want to switch on this, but should rather
|
|
1024 |
just try and set permissions and let them be either stored or not.
|
|
1025 |
This is intended mainly for the use of the test suite.
|
|
1026 |
|
|
1027 |
Warning: this is not guaranteed to be accurate as sometimes we can't
|
|
1028 |
be sure: for example with vfat mounted on unix, or a windows sftp
|
|
1029 |
server."""
|
|
1030 |
# TODO: Perhaps return a e.g. TransportCharacteristics that can answer
|
|
1031 |
# several questions about the transport.
|
|
1032 |
return False |
|
1033 |
||
907.1.24
by John Arbash Meinel
Remote functionality work. |
1034 |
|
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 |
1035 |
# jam 20060426 For compatibility we copy the functions here
|
1685.1.45
by John Arbash Meinel
Moved url functions into bzrlib.urlutils |
1036 |
# TODO: The should be marked as deprecated
|
1037 |
urlescape = urlutils.escape |
|
1038 |
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 |
1039 |
_urlRE = re.compile(r'^(?P<proto>[^:/\\]+)://(?P<path>.*)$') |
1040 |
||
1041 |
||
1393.2.4
by John Arbash Meinel
All tests pass. |
1042 |
def get_transport(base): |
1185.70.3
by Martin Pool
Various updates to make storage branch mergeable: |
1043 |
"""Open a transport to access a URL or directory.
|
1044 |
||
1045 |
base is either a URL or a directory name.
|
|
1046 |
"""
|
|
2241.3.6
by ghigo
Upgraded to the latest bzr.dev |
1047 |
|
907.1.13
by John Arbash Meinel
Fixed bzr root. |
1048 |
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:/ |
1049 |
base = '.' |
1843.1.1
by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info |
1050 |
last_err = None |
1051 |
||
1685.1.33
by John Arbash Meinel
Be more of a Nazi about URLs not being unicode |
1052 |
def convert_path_to_url(base, error_str): |
1053 |
m = _urlRE.match(base) |
|
1054 |
if m: |
|
1055 |
# This looks like a URL, but we weren't able to
|
|
1056 |
# 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 |
1057 |
raise errors.UnsupportedProtocol(base, last_err) |
1685.1.33
by John Arbash Meinel
Be more of a Nazi about URLs not being unicode |
1058 |
# 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 |
1059 |
new_base = urlutils.local_path_to_url(base) |
1908.3.1
by Carl Friedrich Bolz
Clean up some mutter() calls. |
1060 |
# 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 |
1061 |
return new_base |
1062 |
||
1063 |
# Catch any URLs which are passing Unicode rather than ASCII
|
|
1064 |
try: |
|
1065 |
base = base.encode('ascii') |
|
1066 |
except UnicodeError: |
|
1067 |
# Only local paths can be Unicode
|
|
1068 |
base = convert_path_to_url(base, |
|
1069 |
'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:/ |
1070 |
|
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
1071 |
for proto, factory_list in transport_list_registry.iteritems(): |
1685.1.11
by John Arbash Meinel
Not all of the registered transports use :// as part of their path, specifically memory:/ |
1072 |
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 |
1073 |
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:/ |
1074 |
if t: |
1075 |
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 |
1076 |
|
1685.1.33
by John Arbash Meinel
Be more of a Nazi about URLs not being unicode |
1077 |
# We tried all the different protocols, now try one last time
|
1078 |
# as a local protocol
|
|
1079 |
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:/ |
1080 |
|
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
1081 |
# The default handler is the filesystem handler, stored as protocol None
|
2241.2.1
by ghigo
Add the TransportRegistry class |
1082 |
return _try_transport_factories(base, |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
1083 |
transport_list_registry.get(None))[0] |
2241.2.1
by ghigo
Add the TransportRegistry class |
1084 |
|
2164.2.22
by Vincent Ladeuil
Take Aaron's review comments into account. |
1085 |
def do_catching_redirections(action, transport, redirected): |
2164.2.21
by Vincent Ladeuil
Take bundles into account. |
1086 |
"""Execute an action with given transport catching redirections.
|
1087 |
||
1088 |
This is a facility provided for callers needing to follow redirections
|
|
2164.2.25
by Vincent Ladeuil
Fix typos noticed by Aaron. |
1089 |
silently. The silence is relative: it is the caller responsability to
|
2164.2.21
by Vincent Ladeuil
Take bundles into account. |
1090 |
inform the user about each redirection or only inform the user of a user
|
1091 |
via the exception parameter.
|
|
1092 |
||
1093 |
:param action: A callable, what the caller want to do while catching
|
|
1094 |
redirections.
|
|
1095 |
:param transport: The initial transport used.
|
|
1096 |
:param redirected: A callable receiving the redirected transport and the
|
|
1097 |
RedirectRequested exception.
|
|
1098 |
||
1099 |
:return: Whatever 'action' returns
|
|
1100 |
"""
|
|
1101 |
MAX_REDIRECTIONS = 8 |
|
1102 |
||
1103 |
# If a loop occurs, there is little we can do. So we don't try to detect
|
|
1104 |
# them, just getting out if too much redirections occurs. The solution
|
|
1105 |
# is outside: where the loop is defined.
|
|
1106 |
for redirections in range(MAX_REDIRECTIONS): |
|
1107 |
try: |
|
2164.2.22
by Vincent Ladeuil
Take Aaron's review comments into account. |
1108 |
return action(transport) |
2164.2.21
by Vincent Ladeuil
Take bundles into account. |
1109 |
except errors.RedirectRequested, e: |
1110 |
redirection_notice = '%s is%s redirected to %s' % ( |
|
2164.2.22
by Vincent Ladeuil
Take Aaron's review comments into account. |
1111 |
e.source, e.permanently, e.target) |
1112 |
transport = redirected(transport, e, redirection_notice) |
|
2164.2.21
by Vincent Ladeuil
Take bundles into account. |
1113 |
else: |
2164.2.22
by Vincent Ladeuil
Take Aaron's review comments into account. |
1114 |
# Loop exited without resolving redirect ? Either the
|
1115 |
# user has kept a very very very old reference or a loop
|
|
2164.2.25
by Vincent Ladeuil
Fix typos noticed by Aaron. |
1116 |
# occurred in the redirections. Nothing we can cure here:
|
2164.2.22
by Vincent Ladeuil
Take Aaron's review comments into account. |
1117 |
# tell the user. Note that as the user has been informed
|
1118 |
# about each redirection (it is the caller responsibility
|
|
1119 |
# to do that in redirected via the provided
|
|
1120 |
# redirection_notice). The caller may provide more
|
|
2164.2.25
by Vincent Ladeuil
Fix typos noticed by Aaron. |
1121 |
# information if needed (like what file or directory we
|
2164.2.22
by Vincent Ladeuil
Take Aaron's review comments into account. |
1122 |
# were trying to act upon when the redirection loop
|
2164.2.25
by Vincent Ladeuil
Fix typos noticed by Aaron. |
1123 |
# occurred).
|
2164.2.22
by Vincent Ladeuil
Take Aaron's review comments into account. |
1124 |
raise errors.TooManyRedirections |
2164.2.21
by Vincent Ladeuil
Take bundles into account. |
1125 |
|
1126 |
||
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
1127 |
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 |
1128 |
last_err = None |
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
1129 |
for factory in factory_list: |
1130 |
try: |
|
2241.2.1
by ghigo
Add the TransportRegistry class |
1131 |
return factory.get_obj()(base), None |
1996.3.6
by John Arbash Meinel
Find a few places that weren't importing their dependencies. |
1132 |
except errors.DependencyNotPresent, e: |
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
1133 |
mutter("failed to instantiate transport %r for %r: %r" % |
1134 |
(factory, base, e)) |
|
1843.1.1
by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info |
1135 |
last_err = e |
1540.3.12
by Martin Pool
Multiple transports can be registered for any protocol, and they are |
1136 |
continue
|
1843.1.1
by John Arbash Meinel
Update get_transport to raise a nicer error which includes dependency info |
1137 |
return None, last_err |
1185.16.81
by mbp at sourcefrog
[merge] robert |
1138 |
|
1185.16.78
by Martin Pool
- load paramiko sftp transport by default |
1139 |
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1140 |
class Server(object): |
1530.1.21
by Robert Collins
Review feedback fixes. |
1141 |
"""A Transport Server.
|
1142 |
|
|
1143 |
The Server interface provides a server for a given transport. We use
|
|
1144 |
these servers as loopback testing tools. For any given transport the
|
|
1145 |
Servers it provides must either allow writing, or serve the contents
|
|
1146 |
of os.getcwdu() at the time setUp is called.
|
|
1147 |
|
|
1148 |
Note that these are real servers - they must implement all the things
|
|
1149 |
that we want bzr transports to take advantage of.
|
|
1150 |
"""
|
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1151 |
|
1152 |
def setUp(self): |
|
1153 |
"""Setup the server to service requests."""
|
|
1154 |
||
1155 |
def tearDown(self): |
|
1156 |
"""Remove the server and cleanup any resources it owns."""
|
|
1157 |
||
1158 |
def get_url(self): |
|
1530.1.21
by Robert Collins
Review feedback fixes. |
1159 |
"""Return a url for this server.
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1160 |
|
1161 |
If the transport does not represent a disk directory (i.e. it is
|
|
1530.1.21
by Robert Collins
Review feedback fixes. |
1162 |
a database like svn, or a memory only transport, it should return
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1163 |
a connection to a newly established resource for this Server.
|
1530.1.21
by Robert Collins
Review feedback fixes. |
1164 |
Otherwise it should return a url that will provide access to the path
|
1165 |
that was os.getcwdu() when setUp() was called.
|
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1166 |
|
1167 |
Subsequent calls will return the same resource.
|
|
1168 |
"""
|
|
1169 |
raise NotImplementedError |
|
1170 |
||
1530.1.9
by Robert Collins
Test bogus urls with http in the new infrastructure. |
1171 |
def get_bogus_url(self): |
2018.5.104
by Andrew Bennetts
Completely rework chrooted transports. |
1172 |
"""Return a url for this protocol, that will fail to connect.
|
1173 |
|
|
1174 |
This may raise NotImplementedError to indicate that this server cannot
|
|
1175 |
provide bogus urls.
|
|
1176 |
"""
|
|
1530.1.9
by Robert Collins
Test bogus urls with http in the new infrastructure. |
1177 |
raise NotImplementedError |
1178 |
||
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1179 |
|
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
1180 |
class TransportTestProviderAdapter(object): |
1530.1.21
by Robert Collins
Review feedback fixes. |
1181 |
"""A tool to generate a suite testing all transports for a single test.
|
1182 |
||
1183 |
This is done by copying the test once for each transport and injecting
|
|
1184 |
the transport_class and transport_server classes into each copy. Each copy
|
|
1185 |
is also given a new id() to make it easy to identify.
|
|
1186 |
"""
|
|
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
1187 |
|
1188 |
def adapt(self, test): |
|
1996.3.6
by John Arbash Meinel
Find a few places that weren't importing their dependencies. |
1189 |
result = unittest.TestSuite() |
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
1190 |
for klass, server_factory in self._test_permutations(): |
1191 |
new_test = deepcopy(test) |
|
1192 |
new_test.transport_class = klass |
|
1193 |
new_test.transport_server = server_factory |
|
1530.1.3
by Robert Collins
transport implementations now tested consistently. |
1194 |
def make_new_test_id(): |
1195 |
new_id = "%s(%s)" % (new_test.id(), server_factory.__name__) |
|
1196 |
return lambda: new_id |
|
1197 |
new_test.id = make_new_test_id() |
|
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
1198 |
result.addTest(new_test) |
1199 |
return result |
|
1200 |
||
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. |
1201 |
def get_transport_test_permutations(self, module): |
1202 |
"""Get the permutations module wants to have tested."""
|
|
1963.2.6
by Robey Pointer
pychecker is on crack; go back to using 'is None'. |
1203 |
if getattr(module, 'get_test_permutations', None) is None: |
2477.1.7
by Martin Pool
test_transport must provide get_test_permutations |
1204 |
raise AssertionError("transport module %s doesn't provide get_test_permutations()" |
1540.3.6
by Martin Pool
[merge] update from bzr.dev |
1205 |
% module.__name__) |
2477.1.7
by Martin Pool
test_transport must provide get_test_permutations |
1206 |
##warning("transport module %s doesn't provide get_test_permutations()"
|
1207 |
## % module.__name__)
|
|
1540.3.6
by Martin Pool
[merge] update from bzr.dev |
1208 |
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. |
1209 |
return module.get_test_permutations() |
1210 |
||
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
1211 |
def _test_permutations(self): |
1212 |
"""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. |
1213 |
result = [] |
1214 |
for module in _get_transport_modules(): |
|
1534.7.70
by abentley
Fix bug when no paramiko |
1215 |
try: |
1216 |
result.extend(self.get_transport_test_permutations(reduce(getattr, |
|
1217 |
(module).split('.')[1:], |
|
1185.71.1
by John Arbash Meinel
Allow selftest to run, even if we can't load a transport. |
1218 |
__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. |
1219 |
except errors.DependencyNotPresent, e: |
1220 |
# Continue even if a dependency prevents us
|
|
1221 |
# from running this test
|
|
1534.7.70
by abentley
Fix bug when no paramiko |
1222 |
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. |
1223 |
return result |
1594.2.24
by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching. |
1224 |
|
1225 |
||
1226 |
class TransportLogger(object): |
|
1227 |
"""Adapt a transport to get clear logging data on api calls.
|
|
1228 |
|
|
1229 |
Feel free to extend to log whatever calls are of interest.
|
|
1230 |
"""
|
|
1231 |
||
1232 |
def __init__(self, adapted): |
|
1233 |
self._adapted = adapted |
|
1234 |
self._calls = [] |
|
1235 |
||
2164.2.15
by Vincent Ladeuil
Http redirections are not followed by default. Do not use hints |
1236 |
def get(self, name): |
1594.2.24
by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching. |
1237 |
self._calls.append((name,)) |
2164.2.15
by Vincent Ladeuil
Http redirections are not followed by default. Do not use hints |
1238 |
return self._adapted.get(name) |
1594.2.24
by Robert Collins
Make use of the transaction finalisation warning support to implement in-knit caching. |
1239 |
|
1240 |
def __getattr__(self, name): |
|
1241 |
"""Thunk all undefined access through to self._adapted."""
|
|
1242 |
# raise AttributeError, name
|
|
1243 |
return getattr(self._adapted, name) |
|
1244 |
||
1245 |
def readv(self, name, offsets): |
|
1246 |
self._calls.append((name, offsets)) |
|
1247 |
return self._adapted.readv(name, offsets) |
|
1530.1.1
by Robert Collins
Minimal infrastructure to test TransportTestProviderAdapter. |
1248 |
|
1249 |
||
1185.16.81
by mbp at sourcefrog
[merge] robert |
1250 |
# None is the default transport, for things with no url scheme
|
2241.2.9
by ghigo
add the 'file://' prefix to the urlspec topic |
1251 |
register_transport_proto('file://', |
1252 |
help="Access using the standard filesystem (default)") |
|
1185.16.79
by Martin Pool
Load transports when they're first used. |
1253 |
register_lazy_transport('file://', 'bzrlib.transport.local', 'LocalTransport') |
2241.2.3
by ghigo
removed the the registration of the 'None' transport, instead we use the set_default_transport function |
1254 |
transport_list_registry.set_default_transport("file://") |
2241.2.4
by ghigo
removed commented line |
1255 |
|
2241.2.5
by ghigo
add the topics transport |
1256 |
register_transport_proto('sftp://', |
1257 |
help="Access using SFTP (most SSH servers provide SFTP).") |
|
1185.16.79
by Martin Pool
Load transports when they're first used. |
1258 |
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport') |
2164.2.7
by v.ladeuil+lp at free
First implementation of transport hints. |
1259 |
# Decorated http transport
|
2241.2.5
by ghigo
add the topics transport |
1260 |
register_transport_proto('http+urllib://', |
2241.2.11
by ghigo
On the basis of Robert Collins and John Arbash Meinel |
1261 |
# help="Read-only access of branches exported on the web."
|
1262 |
)
|
|
1540.3.23
by Martin Pool
Allow urls like http+pycurl://host/ to use a particular impl |
1263 |
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib', |
1540.3.26
by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet |
1264 |
'HttpTransport_urllib') |
2241.2.5
by ghigo
add the topics transport |
1265 |
register_transport_proto('https+urllib://', |
2241.2.11
by ghigo
On the basis of Robert Collins and John Arbash Meinel |
1266 |
# help="Read-only access of branches exported on the web using SSL."
|
1267 |
)
|
|
1540.3.23
by Martin Pool
Allow urls like http+pycurl://host/ to use a particular impl |
1268 |
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib', |
1540.3.26
by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet |
1269 |
'HttpTransport_urllib') |
2241.2.5
by ghigo
add the topics transport |
1270 |
register_transport_proto('http+pycurl://', |
2241.2.11
by ghigo
On the basis of Robert Collins and John Arbash Meinel |
1271 |
# help="Read-only access of branches exported on the web."
|
1272 |
)
|
|
1540.3.26
by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet |
1273 |
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl', |
1274 |
'PyCurlTransport') |
|
2241.2.5
by ghigo
add the topics transport |
1275 |
register_transport_proto('https+pycurl://', |
2241.2.11
by ghigo
On the basis of Robert Collins and John Arbash Meinel |
1276 |
# help="Read-only access of branches exported on the web using SSL."
|
1277 |
)
|
|
1540.3.26
by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet |
1278 |
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl', |
1279 |
'PyCurlTransport') |
|
2164.2.7
by v.ladeuil+lp at free
First implementation of transport hints. |
1280 |
# Default http transports (last declared wins (if it can be imported))
|
2241.2.5
by ghigo
add the topics transport |
1281 |
register_transport_proto('http://', |
1282 |
help="Read-only access of branches exported on the web.") |
|
1283 |
register_transport_proto('https://', |
|
1284 |
help="Read-only access of branches exported on the web using SSL.") |
|
1540.3.26
by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet |
1285 |
register_lazy_transport('http://', 'bzrlib.transport.http._urllib', |
1286 |
'HttpTransport_urllib') |
|
1287 |
register_lazy_transport('https://', 'bzrlib.transport.http._urllib', |
|
1288 |
'HttpTransport_urllib') |
|
1540.3.7
by Martin Pool
Prepare to select a transport depending on what dependencies can be satisfied. |
1289 |
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport') |
1290 |
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport') |
|
2241.2.4
by ghigo
removed commented line |
1291 |
|
2241.2.5
by ghigo
add the topics transport |
1292 |
register_transport_proto('ftp://', |
1293 |
help="Access using passive FTP.") |
|
1185.36.4
by Daniel Silverstone
Add FTP transport |
1294 |
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport') |
2241.2.5
by ghigo
add the topics transport |
1295 |
register_transport_proto('aftp://', |
1296 |
help="Access using active FTP.") |
|
1185.36.4
by Daniel Silverstone
Add FTP transport |
1297 |
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport') |
2241.2.4
by ghigo
removed commented line |
1298 |
|
2241.2.1
by ghigo
Add the TransportRegistry class |
1299 |
register_transport_proto('memory://') |
1685.1.41
by John Arbash Meinel
memory is now memory://, need to fix the test cases. |
1300 |
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport') |
2241.2.1
by ghigo
Add the TransportRegistry class |
1301 |
register_transport_proto('chroot+') |
2241.3.6
by ghigo
Upgraded to the latest bzr.dev |
1302 |
|
2241.2.5
by ghigo
add the topics transport |
1303 |
register_transport_proto('readonly+', |
2241.2.11
by ghigo
On the basis of Robert Collins and John Arbash Meinel |
1304 |
# help="This modifier converts any transport to be readonly."
|
1305 |
)
|
|
1534.4.9
by Robert Collins
Add a readonly decorator for transports. |
1306 |
register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator') |
2241.2.1
by ghigo
Add the TransportRegistry class |
1307 |
register_transport_proto('fakenfs+') |
1558.10.2
by Robert Collins
Refactor the FakeNFS support into a TransportDecorator. |
1308 |
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator') |
2241.2.1
by ghigo
Add the TransportRegistry class |
1309 |
register_transport_proto('vfat+') |
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
1310 |
register_lazy_transport('vfat+', |
1608.2.4
by Martin Pool
[broken] Add FakeFVATTransport |
1311 |
'bzrlib.transport.fakevfat', |
1312 |
'FakeVFATTransportDecorator') |
|
2241.2.5
by ghigo
add the topics transport |
1313 |
register_transport_proto('bzr://', |
1314 |
help="Fast access using the Bazaar smart server.") |
|
1315 |
||
1910.19.1
by Andrew Bennetts
Support bzr:// urls to work with the new RPC-based transport which will be used |
1316 |
register_lazy_transport('bzr://', |
2018.5.20
by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts) |
1317 |
'bzrlib.transport.remote', |
2413.2.1
by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc. |
1318 |
'RemoteTCPTransport') |
2241.2.5
by ghigo
add the topics transport |
1319 |
register_transport_proto('bzr+http://', |
2241.2.11
by ghigo
On the basis of Robert Collins and John Arbash Meinel |
1320 |
# help="Fast access using the Bazaar smart server over HTTP."
|
1321 |
)
|
|
2190.1.3
by John Arbash Meinel
Implement bzr+http:// |
1322 |
register_lazy_transport('bzr+http://', |
2018.5.43
by Andrew Bennetts
Merge from bzr.dev. |
1323 |
'bzrlib.transport.remote', |
2413.2.1
by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc. |
1324 |
'RemoteHTTPTransport') |
2241.2.5
by ghigo
add the topics transport |
1325 |
register_transport_proto('bzr+ssh://', |
1326 |
help="Fast access using the Bazaar smart server over SSH.") |
|
1752.2.73
by Andrew Bennetts
Define (and register as bzr+ssh://) SmartSSHTransport, factor out an SSHSubprocess from SFTPSubprocess, and make SmartTransport connect lazily rather than in the constructor. |
1327 |
register_lazy_transport('bzr+ssh://', |
2018.5.20
by Andrew Bennetts
Move bzrlib/transport/smart/_smart.py to bzrlib/transport/remote.py and rename SmartTransport to RemoteTransport (Robert Collins, Andrew Bennetts) |
1328 |
'bzrlib.transport.remote', |
2413.2.1
by Andrew Bennetts
Rename Smart.*Transport classes to RemoteTransport, RemoteTCPTransport, etc. |
1329 |
'RemoteSSHTransport') |