1185.11.19
by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings. |
1 |
# Copyright (C) 2005 Canonical Ltd
|
2 |
||
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.
|
|
7 |
||
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.
|
|
12 |
||
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
|
|
16 |
"""Transport is an abstraction layer to handle file access.
|
|
17 |
||
18 |
The abstraction is to allow access from the local filesystem, as well
|
|
19 |
as remote (such as http or sftp).
|
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
20 |
"""
|
21 |
||
907.1.45
by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary. |
22 |
from bzrlib.trace import mutter |
1185.11.9
by John Arbash Meinel
Most tests pass, some problems with unavailable socket recv |
23 |
from bzrlib.errors import (BzrError, |
24 |
TransportError, TransportNotPossible, NonRelativePath, |
|
25 |
NoSuchFile, FileExists, PermissionDenied, |
|
26 |
ConnectionReset) |
|
907.1.45
by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary. |
27 |
|
28 |
_protocol_handlers = { |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
29 |
}
|
30 |
||
907.1.45
by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary. |
31 |
def register_transport(prefix, klass, override=True): |
32 |
global _protocol_handlers |
|
33 |
||
34 |
if _protocol_handlers.has_key(prefix): |
|
35 |
if override: |
|
36 |
mutter('overriding transport: %s => %s' % (prefix, klass.__name__)) |
|
37 |
_protocol_handlers[prefix] = klass |
|
38 |
else: |
|
39 |
mutter('registering transport: %s => %s' % (prefix, klass.__name__)) |
|
40 |
_protocol_handlers[prefix] = klass |
|
41 |
||
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
42 |
class Transport(object): |
43 |
"""This class encapsulates methods for retrieving or putting a file
|
|
44 |
from/to a storage location.
|
|
45 |
||
46 |
Most functions have a _multi variant, which allows you to queue up
|
|
47 |
multiple requests. They generally have a dumb base implementation
|
|
48 |
which just iterates over the arguments, but smart Transport
|
|
49 |
implementations can do pipelining.
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
50 |
In general implementations should support having a generator or a list
|
51 |
as an argument (ie always iterate, never index)
|
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
52 |
"""
|
53 |
||
54 |
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. |
55 |
super(Transport, self).__init__() |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
56 |
self.base = base |
57 |
||
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
58 |
def clone(self, offset=None): |
59 |
"""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. |
60 |
using a subdirectory or parent directory. This allows connections
|
61 |
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. |
62 |
"""
|
63 |
raise NotImplementedError |
|
64 |
||
907.1.32
by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate. |
65 |
def should_cache(self): |
66 |
"""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. |
67 |
"""
|
907.1.32
by John Arbash Meinel
Renaming is_remote to should_cache as it is more appropriate. |
68 |
return False |
907.1.22
by John Arbash Meinel
Fixed some encoding issues, added is_remote function for Transport objects. |
69 |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
70 |
def _pump(self, from_file, to_file): |
71 |
"""Most children will need to copy from one file-like
|
|
72 |
object or string to another one.
|
|
73 |
This just gives them something easy to call.
|
|
74 |
"""
|
|
75 |
if isinstance(from_file, basestring): |
|
907.1.8
by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport |
76 |
to_file.write(from_file) |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
77 |
else: |
78 |
from bzrlib.osutils import pumpfile |
|
79 |
pumpfile(from_file, to_file) |
|
80 |
||
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
81 |
def _get_total(self, multi): |
82 |
"""Try to figure out how many entries are in multi,
|
|
83 |
but if not possible, return None.
|
|
84 |
"""
|
|
85 |
try: |
|
86 |
return len(multi) |
|
87 |
except TypeError: # We can't tell how many, because relpaths is a generator |
|
88 |
return None |
|
89 |
||
90 |
def _update_pb(self, pb, msg, count, total): |
|
91 |
"""Update the progress bar based on the current count
|
|
92 |
and total available, total may be None if it was
|
|
93 |
not possible to determine.
|
|
94 |
"""
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
95 |
if pb is None: |
96 |
return
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
97 |
if total is None: |
98 |
pb.update(msg, count, count+1) |
|
99 |
else: |
|
100 |
pb.update(msg, count, total) |
|
101 |
||
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
102 |
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. |
103 |
"""Iterate over all entries in multi, passing them to func,
|
104 |
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. |
105 |
|
106 |
:param expand: If True, the entries will be passed to the function
|
|
107 |
by expanding the tuple. If False, it will be passed
|
|
108 |
as a single parameter.
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
109 |
"""
|
110 |
total = self._get_total(multi) |
|
111 |
count = 0 |
|
112 |
for entry in multi: |
|
113 |
self._update_pb(pb, msg, count, total) |
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
114 |
if expand: |
115 |
func(*entry) |
|
116 |
else: |
|
117 |
func(entry) |
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
118 |
count += 1 |
119 |
return count |
|
120 |
||
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
121 |
def abspath(self, relpath): |
122 |
"""Return the full url to the given relative path.
|
|
123 |
This can be supplied with a string or a list
|
|
124 |
"""
|
|
125 |
raise NotImplementedError |
|
126 |
||
127 |
def relpath(self, abspath): |
|
128 |
"""Return the local path portion from a given absolute path.
|
|
129 |
"""
|
|
130 |
raise NotImplementedError |
|
131 |
||
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
132 |
def has(self, relpath): |
133 |
"""Does the target location exist?"""
|
|
134 |
raise NotImplementedError |
|
135 |
||
907.1.36
by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class. |
136 |
def has_multi(self, relpaths, pb=None): |
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
137 |
"""Return True/False for each entry in relpaths"""
|
138 |
total = self._get_total(relpaths) |
|
139 |
count = 0 |
|
140 |
for relpath in relpaths: |
|
907.1.36
by John Arbash Meinel
Moving the multi-get functionality higher up into the Branch class. |
141 |
self._update_pb(pb, 'has', count, total) |
907.1.34
by John Arbash Meinel
Fixing append(), cleaning up function locations. |
142 |
yield self.has(relpath) |
143 |
count += 1 |
|
144 |
||
907.1.50
by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown. |
145 |
def get(self, relpath): |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
146 |
"""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 |
147 |
|
148 |
:param relpath: The relative path to the file
|
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
149 |
"""
|
150 |
raise NotImplementedError |
|
151 |
||
907.1.50
by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown. |
152 |
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. |
153 |
"""Get a list of file-like objects, one for each entry in relpaths.
|
154 |
||
155 |
: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. |
156 |
:param pb: An optional ProgressBar for indicating percent done.
|
157 |
: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. |
158 |
"""
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
159 |
# TODO: Consider having this actually buffer the requests,
|
160 |
# in the default mode, it probably won't give worse performance,
|
|
161 |
# and all children wouldn't have to implement buffering
|
|
907.1.16
by John Arbash Meinel
Fixing a few cut&paste typos. |
162 |
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. |
163 |
count = 0 |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
164 |
for relpath in relpaths: |
907.1.16
by John Arbash Meinel
Fixing a few cut&paste typos. |
165 |
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. |
166 |
yield self.get(relpath) |
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
167 |
count += 1 |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
168 |
|
1185.11.21
by John Arbash Meinel
Added implementations and tests for get_partial |
169 |
def get_partial(self, relpath, start, length=None): |
170 |
"""Get just part of a file.
|
|
171 |
||
172 |
:param relpath: Path to the file, relative to base
|
|
173 |
:param start: The starting position to read from
|
|
174 |
:param length: The length to read. A length of None indicates
|
|
175 |
read to the end of the file.
|
|
176 |
:return: A file-like object containing at least the specified bytes.
|
|
177 |
Some implementations may return objects which can be read
|
|
178 |
past this length, but this is not guaranteed.
|
|
179 |
"""
|
|
180 |
raise NotImplementedError |
|
181 |
||
182 |
def get_partial_multi(self, offsets, pb=None): |
|
183 |
"""Put a set of files or strings into the location.
|
|
184 |
||
185 |
Requesting multiple portions of the same file can be dangerous.
|
|
186 |
||
187 |
:param offsets: A list of tuples of relpath, start, length
|
|
188 |
[(path1, start1, length1),
|
|
189 |
(path2, start2, length2),
|
|
190 |
(path3, start3), ...]
|
|
191 |
length is optional, defaulting to None
|
|
192 |
:param pb: An optional ProgressBar for indicating percent done.
|
|
193 |
:return: A generator of file-like objects.
|
|
194 |
"""
|
|
195 |
total = self._get_total(offsets) |
|
196 |
count = 0 |
|
197 |
for offset in offsets: |
|
198 |
self._update_pb(pb, 'get_partial', count, total) |
|
199 |
yield self.get_partial(*offset) |
|
200 |
count += 1 |
|
201 |
||
907.1.50
by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown. |
202 |
def put(self, relpath, f): |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
203 |
"""Copy the file-like or string object into the location.
|
907.1.20
by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8 |
204 |
|
205 |
:param relpath: Location to put the contents, relative to base.
|
|
206 |
:param f: File-like or string object.
|
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
207 |
"""
|
208 |
raise NotImplementedError |
|
209 |
||
907.1.50
by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown. |
210 |
def put_multi(self, files, pb=None): |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
211 |
"""Put a set of files or strings into the location.
|
212 |
||
213 |
: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. |
214 |
:param pb: An optional ProgressBar for indicating percent done.
|
215 |
:return: The number of files copied.
|
|
216 |
"""
|
|
1185.11.20
by John Arbash Meinel
Added some more test cases to verify generators work. |
217 |
return self._iterate_over(files, self.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. |
218 |
|
219 |
def mkdir(self, relpath): |
|
220 |
"""Create a directory at the given path."""
|
|
221 |
raise NotImplementedError |
|
222 |
||
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 |
223 |
def mkdir_multi(self, relpaths, pb=None): |
224 |
"""Create a group of directories"""
|
|
225 |
return self._iterate_over(relpaths, self.mkdir, pb, 'mkdir', expand=False) |
|
226 |
||
907.1.50
by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown. |
227 |
def append(self, relpath, f): |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
228 |
"""Append the text in the file-like or string object to
|
229 |
the supplied location.
|
|
230 |
"""
|
|
231 |
raise NotImplementedError |
|
232 |
||
1185.11.19
by John Arbash Meinel
Testing put and append, also testing agaist file-like objects as well as strings. |
233 |
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. |
234 |
"""Append the text in each file-like or string object to
|
235 |
the supplied location.
|
|
907.1.2
by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport. |
236 |
|
237 |
:param files: A set of (path, f) entries
|
|
238 |
: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. |
239 |
"""
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
240 |
return self._iterate_over(files, self.append, pb, 'append', expand=True) |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
241 |
|
242 |
def copy(self, rel_from, rel_to): |
|
243 |
"""Copy the item at rel_from to the location at rel_to"""
|
|
244 |
raise NotImplementedError |
|
245 |
||
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
246 |
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. |
247 |
"""Copy a bunch of entries.
|
248 |
|
|
249 |
:param relpaths: A list of tuples of the form [(from, to), (from, to),...]
|
|
250 |
"""
|
|
251 |
# This is the non-pipelined implementation, so that
|
|
252 |
# implementors don't have to implement everything.
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
253 |
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. |
254 |
|
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
255 |
def copy_to(self, relpaths, other, pb=None): |
256 |
"""Copy a set of entries from self into another Transport.
|
|
257 |
||
258 |
:param relpaths: A list/generator of entries to be copied.
|
|
259 |
"""
|
|
260 |
# The dummy implementation just does a simple get + put
|
|
261 |
def copy_entry(path): |
|
907.1.50
by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown. |
262 |
other.put(path, self.get(path)) |
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
263 |
|
264 |
return self._iterate_over(relpaths, copy_entry, pb, 'copy_to', expand=False) |
|
265 |
||
907.1.57
by John Arbash Meinel
Trying to get pipelined http library working + tests. |
266 |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
267 |
def move(self, rel_from, rel_to): |
268 |
"""Move the item at rel_from to the location at rel_to"""
|
|
269 |
raise NotImplementedError |
|
270 |
||
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
271 |
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. |
272 |
"""Move a bunch of entries.
|
273 |
|
|
274 |
:param relpaths: A list of tuples of the form [(from1, to1), (from2, to2),...]
|
|
275 |
"""
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
276 |
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. |
277 |
|
278 |
def move_multi_to(self, relpaths, rel_to): |
|
279 |
"""Move a bunch of entries to a single location.
|
|
280 |
This differs from move_multi in that you give a list of from, and
|
|
281 |
a single destination, rather than multiple destinations.
|
|
282 |
||
283 |
:param relpaths: A list of relative paths [from1, from2, from3, ...]
|
|
284 |
:param rel_to: A directory where each entry should be placed.
|
|
285 |
"""
|
|
286 |
# This is not implemented, because you need to do special tricks to
|
|
287 |
# extract the basename, and add it to rel_to
|
|
288 |
raise NotImplementedError |
|
289 |
||
290 |
def delete(self, relpath): |
|
291 |
"""Delete the item at relpath"""
|
|
292 |
raise NotImplementedError |
|
293 |
||
907.1.28
by John Arbash Meinel
Added pb to function that were missing, implemented a basic double-dispatch copy_to function. |
294 |
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. |
295 |
"""Queue up a bunch of deletes to be done.
|
296 |
"""
|
|
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
297 |
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. |
298 |
|
299 |
def stat(self, relpath): |
|
300 |
"""Return the stat information for a file.
|
|
301 |
WARNING: This may not be implementable for all protocols, so use
|
|
302 |
sparingly.
|
|
303 |
"""
|
|
304 |
raise NotImplementedError |
|
305 |
||
306 |
def stat_multi(self, relpaths, pb=None): |
|
307 |
"""Stat multiple files and return the information.
|
|
308 |
"""
|
|
309 |
#TODO: Is it worth making this a generator instead of a
|
|
310 |
# returning a list?
|
|
311 |
stats = [] |
|
312 |
def gather(path): |
|
313 |
stats.append(self.stat(path)) |
|
314 |
||
907.1.14
by John Arbash Meinel
Handling some transport functions which take only a single argument. |
315 |
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. |
316 |
return stats |
317 |
||
1400.1.1
by Robert Collins
implement a basic test for the ui branch command from http servers |
318 |
def listable(self): |
319 |
"""Return True if this store supports listing."""
|
|
320 |
raise NotImplementedError |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
321 |
|
322 |
def list_dir(self, relpath): |
|
323 |
"""Return a list of all files at the given location.
|
|
324 |
WARNING: many transports do not support this, so trying avoid using
|
|
325 |
it if at all possible.
|
|
326 |
"""
|
|
1400.1.1
by Robert Collins
implement a basic test for the ui branch command from http servers |
327 |
raise TransportNotPossible("This transport has not " |
328 |
"implemented list_dir.") |
|
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
329 |
|
907.1.24
by John Arbash Meinel
Remote functionality work. |
330 |
def lock_read(self, relpath): |
331 |
"""Lock the given file for shared (read) access.
|
|
332 |
WARNING: many transports do not support this, so trying avoid using it
|
|
333 |
||
334 |
:return: A lock object, which should contain an unlock() function.
|
|
335 |
"""
|
|
336 |
raise NotImplementedError |
|
337 |
||
338 |
def lock_write(self, relpath): |
|
339 |
"""Lock the given file for exclusive (write) access.
|
|
340 |
WARNING: many transports do not support this, so trying avoid using it
|
|
341 |
||
342 |
:return: A lock object, which should contain an unlock() function.
|
|
343 |
"""
|
|
344 |
raise NotImplementedError |
|
345 |
||
346 |
||
1393.2.4
by John Arbash Meinel
All tests pass. |
347 |
def get_transport(base): |
907.1.45
by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary. |
348 |
global _protocol_handlers |
907.1.13
by John Arbash Meinel
Fixed bzr root. |
349 |
if base is None: |
350 |
base = '.' |
|
907.1.45
by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary. |
351 |
for proto, klass in _protocol_handlers.iteritems(): |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
352 |
if proto is not None and base.startswith(proto): |
353 |
return klass(base) |
|
354 |
# The default handler is the filesystem handler
|
|
355 |
# which has a lookup of None
|
|
907.1.45
by John Arbash Meinel
Switch to registering protocol handlers, rather than just updating a dictionary. |
356 |
return _protocol_handlers[None](base) |
907.1.1
by John Arbash Meinel
Reworking the Branch and Store code to support an abstracted filesystem layer. |
357 |
|
358 |
# Local transport should always be initialized
|
|
1185.11.1
by John Arbash Meinel
(broken) Transport work is merged in. Tests do not pass yet. |
359 |
import bzrlib.transport.local |