22
22
from bzrlib.trace import mutter
23
from bzrlib.errors import (BzrError,
24
TransportError, TransportNotPossible, NonRelativePath,
25
NoSuchFile, FileExists, PermissionDenied,
23
import bzrlib.errors as errors
28
27
_protocol_handlers = {
57
56
super(Transport, self).__init__()
59
def _translate_error(self, e, path, raise_generic=True):
60
"""Translate an IOError or OSError into an appropriate bzr error.
62
This handles things like ENOENT, ENOTDIR, EEXIST, and EACCESS
64
if hasattr(e, 'errno'):
65
if e.errno in (errno.ENOENT, errno.ENOTDIR):
66
raise errors.NoSuchFile(path, extra=e)
67
# I would rather use errno.EFOO, but there doesn't seem to be
68
# any matching for 267
69
# This is the error when doing a listdir on a file:
70
# WindowsError: [Errno 267] The directory name is invalid
71
if sys.platform == 'win32' and e.errno in (errno.ESRCH, 267):
72
raise errors.NoSuchFile(path, extra=e)
73
if e.errno == errno.EEXIST:
74
raise errors.FileExists(path, extra=e)
75
if e.errno == errno.EACCES:
76
raise errors.PermissionDenied(path, extra=e)
78
raise errors.TransportError(orig_error=e)
60
80
def clone(self, offset=None):
61
81
"""Return a new Transport object, cloned from the current location,
62
82
using a subdirectory or parent directory. This allows connections
137
157
start with our base, but still be a relpath once aliasing is
160
# TODO: This might want to use bzrlib.osutils.relpath
161
# but we have to watch out because of the prefix issues
140
162
if not abspath.startswith(self.base):
141
raise NonRelativePath('path %r is not under base URL %r'
142
% (abspath, self.base))
163
raise errors.PathNotChild(abspath, self.base)
143
164
pl = len(self.base)
144
165
return abspath[pl:].lstrip('/')
200
221
yield self.get(relpath)
203
def put(self, relpath, f):
224
def put(self, relpath, f, mode=None):
204
225
"""Copy the file-like or string object into the location.
206
227
:param relpath: Location to put the contents, relative to base.
207
228
:param f: File-like or string object.
229
:param mode: The mode for the newly created file,
230
None means just use the default
209
232
raise NotImplementedError
211
def put_multi(self, files, pb=None):
234
def put_multi(self, files, mode=None, pb=None):
212
235
"""Put a set of files or strings into the location.
214
237
:param files: A list of tuples of relpath, file object [(path1, file1), (path2, file2),...]
215
238
:param pb: An optional ProgressBar for indicating percent done.
239
:param mode: The mode for the newly created files
216
240
:return: The number of files copied.
218
return self._iterate_over(files, self.put, pb, 'put', expand=True)
243
self.put(path, f, mode=mode)
244
return self._iterate_over(files, put, pb, 'put', expand=True)
220
def mkdir(self, relpath):
246
def mkdir(self, relpath, mode=None):
221
247
"""Create a directory at the given path."""
222
248
raise NotImplementedError
224
def mkdir_multi(self, relpaths, pb=None):
250
def mkdir_multi(self, relpaths, mode=None, pb=None):
225
251
"""Create a group of directories"""
226
return self._iterate_over(relpaths, self.mkdir, pb, 'mkdir', expand=False)
253
self.mkdir(path, mode=mode)
254
return self._iterate_over(relpaths, mkdir, pb, 'mkdir', expand=False)
228
256
def append(self, relpath, f):
229
257
"""Append the text in the file-like or string object to
253
281
# implementors don't have to implement everything.
254
282
return self._iterate_over(relpaths, self.copy, pb, 'copy', expand=True)
256
def copy_to(self, relpaths, other, pb=None):
284
def copy_to(self, relpaths, other, mode=None, pb=None):
257
285
"""Copy a set of entries from self into another Transport.
259
287
:param relpaths: A list/generator of entries to be copied.
288
:param mode: This is the target mode for the newly created files
260
289
TODO: This interface needs to be updated so that the target location
261
290
can be different from the source location.
263
292
# The dummy implementation just does a simple get + put
264
293
def copy_entry(path):
265
other.put(path, self.get(path))
294
other.put(path, self.get(path), mode=mode)
267
296
return self._iterate_over(relpaths, copy_entry, pb, 'copy_to', expand=False)