~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

Merge from integration.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
"""
21
21
 
22
22
from bzrlib.trace import mutter
23
 
from bzrlib.errors import (BzrError, 
24
 
    TransportError, TransportNotPossible, NonRelativePath,
25
 
    NoSuchFile, FileExists, PermissionDenied,
26
 
    ConnectionReset)
 
23
import bzrlib.errors as errors
 
24
import errno
 
25
import sys
27
26
 
28
27
_protocol_handlers = {
29
28
}
57
56
        super(Transport, self).__init__()
58
57
        self.base = base
59
58
 
 
59
    def _translate_error(self, e, path, raise_generic=True):
 
60
        """Translate an IOError or OSError into an appropriate bzr error.
 
61
 
 
62
        This handles things like ENOENT, ENOTDIR, EEXIST, and EACCESS
 
63
        """
 
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)
 
77
        if raise_generic:
 
78
            raise errors.TransportError(orig_error=e)
 
79
 
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 
138
158
        resolved.
139
159
        """
 
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('/')
145
166
 
200
221
            yield self.get(relpath)
201
222
            count += 1
202
223
 
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.
205
226
 
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
208
231
        """
209
232
        raise NotImplementedError
210
233
 
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.
213
236
 
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.
217
241
        """
218
 
        return self._iterate_over(files, self.put, pb, 'put', expand=True)
 
242
        def put(path, f):
 
243
            self.put(path, f, mode=mode)
 
244
        return self._iterate_over(files, put, pb, 'put', expand=True)
219
245
 
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
223
249
 
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)
 
252
        def mkdir(path):
 
253
            self.mkdir(path, mode=mode)
 
254
        return self._iterate_over(relpaths, mkdir, pb, 'mkdir', expand=False)
227
255
 
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)
255
283
 
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.
258
286
 
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.
262
291
        """
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)
266
295
 
267
296
        return self._iterate_over(relpaths, copy_entry, pb, 'copy_to', expand=False)
268
297
 
332
361
        WARNING: many transports do not support this, so trying avoid using
333
362
        it if at all possible.
334
363
        """
335
 
        raise TransportNotPossible("This transport has not "
336
 
                                   "implemented list_dir.")
 
364
        raise errors.TransportNotPossible("This transport has not "
 
365
                                          "implemented list_dir.")
337
366
 
338
367
    def lock_read(self, relpath):
339
368
        """Lock the given file for shared (read) access.
355
384
def get_transport(base):
356
385
    global _protocol_handlers
357
386
    if base is None:
358
 
        base = '.'
 
387
        base = u'.'
 
388
    else:
 
389
        base = unicode(base)
359
390
    for proto, klass in _protocol_handlers.iteritems():
360
391
        if proto is not None and base.startswith(proto):
361
392
            return klass(base)