/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/ftp/__init__.py

  • Committer: Martin Pool
  • Date: 2010-10-08 04:38:25 UTC
  • mfrom: (5462 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5478.
  • Revision ID: mbp@sourcefrog.net-20101008043825-b181r8bo5r3qwb6j
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
16
17
"""Implementation of Transport over ftp.
17
18
 
18
19
Written by Daniel Silverstone <dsilvers@digital-scurf.org> with serious
39
40
    osutils,
40
41
    urlutils,
41
42
    )
 
43
from bzrlib.symbol_versioning import (
 
44
    DEPRECATED_PARAMETER,
 
45
    deprecated_in,
 
46
    deprecated_passed,
 
47
    warn,
 
48
    )
42
49
from bzrlib.trace import mutter, warning
43
50
from bzrlib.transport import (
44
51
    AppendBasedFileStream,
163
170
        connection, credentials = self._create_connection(credentials)
164
171
        self._set_connection(connection, credentials)
165
172
 
166
 
    def _translate_perm_error(self, err, path, extra=None,
 
173
    def disconnect(self):
 
174
        connection = self._get_connection()
 
175
        if connection is not None:
 
176
            connection.close()
 
177
 
 
178
    def _translate_ftp_error(self, err, path, extra=None,
167
179
                              unknown_exc=FtpPathError):
168
 
        """Try to translate an ftplib.error_perm exception.
 
180
        """Try to translate an ftplib exception to a bzrlib exception.
169
181
 
170
182
        :param err: The error to translate into a bzr error
171
183
        :param path: The path which had problems
173
185
        :param unknown_exc: If None, we will just raise the original exception
174
186
                    otherwise we raise unknown_exc(path, extra=extra)
175
187
        """
 
188
        # ftp error numbers are very generic, like "451: Requested action aborted,
 
189
        # local error in processing" so unfortunately we have to match by
 
190
        # strings.
176
191
        s = str(err).lower()
177
192
        if not extra:
178
193
            extra = str(err)
187
202
            or 'file/directory not found' in s # filezilla server
188
203
            # Microsoft FTP-Service RNFR reply if file not found
189
204
            or (s.startswith('550 ') and 'unable to rename to' in extra)
 
205
            # if containing directory doesn't exist, suggested by
 
206
            # <https://bugs.edge.launchpad.net/bzr/+bug/224373>
 
207
            or (s.startswith('550 ') and "can't find folder" in s)
190
208
            ):
191
209
            raise errors.NoSuchFile(path, extra=extra)
192
 
        if ('file exists' in s):
 
210
        elif ('file exists' in s):
193
211
            raise errors.FileExists(path, extra=extra)
194
 
        if ('not a directory' in s):
 
212
        elif ('not a directory' in s):
195
213
            raise errors.PathError(path, extra=extra)
 
214
        elif 'directory not empty' in s:
 
215
            raise errors.DirectoryNotEmpty(path, extra=extra)
196
216
 
197
217
        mutter('unable to understand error for path: %s: %s', path, err)
198
218
 
205
225
        #raise TransportError(msg='Error for path: %s' % (path,), orig_error=e)
206
226
        raise
207
227
 
208
 
    def _remote_path(self, relpath):
209
 
        # XXX: It seems that ftplib does not handle Unicode paths
210
 
        # at the same time, medusa won't handle utf8 paths So if
211
 
        # we .encode(utf8) here (see ConnectedTransport
212
 
        # implementation), then we get a Server failure.  while
213
 
        # if we use str(), we get a UnicodeError, and the test
214
 
        # suite just skips testing UnicodePaths.
215
 
        relative = str(urlutils.unescape(relpath))
216
 
        remote_path = self._combine_paths(self._path, relative)
217
 
        return remote_path
218
 
 
219
228
    def has(self, relpath):
220
229
        """Does the target location exist?"""
221
230
        # FIXME jam 20060516 We *do* ask about directories in the test suite
237
246
            mutter("FTP has not: %s: %s", abspath, e)
238
247
            return False
239
248
 
240
 
    def get(self, relpath, decode=False, retries=0):
 
249
    def get(self, relpath, decode=DEPRECATED_PARAMETER, retries=0):
241
250
        """Get the file at the given relative path.
242
251
 
243
252
        :param relpath: The relative path to the file
247
256
        We're meant to return a file-like object which bzr will
248
257
        then read from. For now we do this via the magic of StringIO
249
258
        """
250
 
        # TODO: decode should be deprecated
 
259
        if deprecated_passed(decode):
 
260
            warn(deprecated_in((2,3,0)) %
 
261
                 '"decode" parameter to FtpTransport.get()',
 
262
                 DeprecationWarning, stacklevel=2)
251
263
        try:
252
264
            mutter("FTP get: %s", self._remote_path(relpath))
253
265
            f = self._get_FTP()
319
331
                    return len(bytes)
320
332
                else:
321
333
                    return fp.counted_bytes
322
 
            except (ftplib.error_temp,EOFError), e:
323
 
                warning("Failure during ftp PUT. Deleting temporary file.")
 
334
            except (ftplib.error_temp, EOFError), e:
 
335
                warning("Failure during ftp PUT of %s: %s. Deleting temporary file."
 
336
                    % (tmp_abspath, e, ))
324
337
                try:
325
338
                    f.delete(tmp_abspath)
326
339
                except:
329
342
                    raise e
330
343
                raise
331
344
        except ftplib.error_perm, e:
332
 
            self._translate_perm_error(e, abspath, extra='could not store',
 
345
            self._translate_ftp_error(e, abspath, extra='could not store',
333
346
                                       unknown_exc=errors.NoSuchFile)
334
347
        except ftplib.error_temp, e:
335
348
            if retries > _number_of_retries:
336
 
                raise errors.TransportError("FTP temporary error during PUT %s. Aborting."
337
 
                                     % self.abspath(relpath), orig_error=e)
 
349
                raise errors.TransportError(
 
350
                    "FTP temporary error during PUT %s: %s. Aborting."
 
351
                    % (self.abspath(relpath), e), orig_error=e)
338
352
            else:
339
353
                warning("FTP temporary error: %s. Retrying.", str(e))
340
354
                self._reconnect()
355
369
        try:
356
370
            mutter("FTP mkd: %s", abspath)
357
371
            f = self._get_FTP()
358
 
            f.mkd(abspath)
 
372
            try:
 
373
                f.mkd(abspath)
 
374
            except ftplib.error_reply, e:
 
375
                # <https://bugs.launchpad.net/bzr/+bug/224373> Microsoft FTP
 
376
                # server returns "250 Directory created." which is kind of
 
377
                # reasonable, 250 meaning "requested file action OK", but not what
 
378
                # Python's ftplib expects.
 
379
                if e[0][:3] == '250':
 
380
                    pass
 
381
                else:
 
382
                    raise
359
383
            self._setmode(relpath, mode)
360
384
        except ftplib.error_perm, e:
361
 
            self._translate_perm_error(e, abspath,
 
385
            self._translate_ftp_error(e, abspath,
362
386
                unknown_exc=errors.FileExists)
363
387
 
364
388
    def open_write_stream(self, relpath, mode=None):
384
408
            f = self._get_FTP()
385
409
            f.rmd(abspath)
386
410
        except ftplib.error_perm, e:
387
 
            self._translate_perm_error(e, abspath, unknown_exc=errors.PathError)
 
411
            self._translate_ftp_error(e, abspath, unknown_exc=errors.PathError)
388
412
 
389
413
    def append_file(self, relpath, f, mode=None):
390
414
        """Append the text in the file-like object into the final
430
454
                self._has_append = False
431
455
                self._fallback_append(relpath, text, mode)
432
456
            else:
433
 
                self._translate_perm_error(e, abspath, extra='error appending',
 
457
                self._translate_ftp_error(e, abspath, extra='error appending',
434
458
                    unknown_exc=errors.NoSuchFile)
435
459
        except ftplib.error_temp, e:
436
460
            if retries > _number_of_retries:
483
507
    def _rename(self, abs_from, abs_to, f):
484
508
        try:
485
509
            f.rename(abs_from, abs_to)
486
 
        except ftplib.error_perm, e:
487
 
            self._translate_perm_error(e, abs_from,
 
510
        except (ftplib.error_temp, ftplib.error_perm), e:
 
511
            self._translate_ftp_error(e, abs_from,
488
512
                ': unable to rename to %r' % (abs_to))
489
513
 
490
514
    def move(self, rel_from, rel_to):
496
520
            f = self._get_FTP()
497
521
            self._rename_and_overwrite(abs_from, abs_to, f)
498
522
        except ftplib.error_perm, e:
499
 
            self._translate_perm_error(e, abs_from,
 
523
            self._translate_ftp_error(e, abs_from,
500
524
                extra='unable to rename to %r' % (rel_to,),
501
525
                unknown_exc=errors.PathError)
502
526
 
520
544
            mutter("FTP rm: %s", abspath)
521
545
            f.delete(abspath)
522
546
        except ftplib.error_perm, e:
523
 
            self._translate_perm_error(e, abspath, 'error deleting',
 
547
            self._translate_ftp_error(e, abspath, 'error deleting',
524
548
                unknown_exc=errors.NoSuchFile)
525
549
 
526
550
    def external_url(self):
541
565
            try:
542
566
                paths = f.nlst(basepath)
543
567
            except ftplib.error_perm, e:
544
 
                self._translate_perm_error(e, relpath,
 
568
                self._translate_ftp_error(e, relpath,
545
569
                                           extra='error with list_dir')
546
570
            except ftplib.error_temp, e:
547
571
                # xs4all's ftp server raises a 450 temp error when listing an
590
614
            f = self._get_FTP()
591
615
            return FtpStatResult(f, abspath)
592
616
        except ftplib.error_perm, e:
593
 
            self._translate_perm_error(e, abspath, extra='error w/ stat')
 
617
            self._translate_ftp_error(e, abspath, extra='error w/ stat')
594
618
 
595
619
    def lock_read(self, relpath):
596
620
        """Lock the given file for shared (read) access.