~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/ftp.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-04-17 00:59:30 UTC
  • mfrom: (1551.15.4 Aaron's mergeable stuff)
  • Revision ID: pqm@pqm.ubuntu.com-20070417005930-rofskshyjsfzrahh
Fix ftp transport with servers that don't support atomic rename

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
import errno
30
30
import ftplib
31
31
import os
 
32
import os.path
32
33
import urllib
33
34
import urlparse
34
35
import select
40
41
 
41
42
from bzrlib import (
42
43
    errors,
 
44
    osutils,
43
45
    urlutils,
44
46
    )
45
47
from bzrlib.trace import mutter, warning
303
305
        :param retries: Number of retries after temporary failures so far
304
306
                        for this operation.
305
307
 
306
 
        TODO: jam 20051215 ftp as a protocol seems to support chmod, but ftplib does not
 
308
        TODO: jam 20051215 ftp as a protocol seems to support chmod, but
 
309
        ftplib does not
307
310
        """
308
311
        abspath = self._abspath(relpath)
309
312
        tmp_abspath = '%s.tmp.%.9f.%d.%d' % (abspath, time.time(),
315
318
            f = self._get_FTP()
316
319
            try:
317
320
                f.storbinary('STOR '+tmp_abspath, fp)
318
 
                f.rename(tmp_abspath, abspath)
 
321
                self._rename_and_overwrite(tmp_abspath, abspath, f)
319
322
            except (ftplib.error_temp,EOFError), e:
320
323
                warning("Failure during ftp PUT. Deleting temporary file.")
321
324
                try:
434
437
    #       to give it its own address as the 'to' location.
435
438
    #       So implement a fancier 'copy()'
436
439
 
 
440
    def rename(self, rel_from, rel_to):
 
441
        abs_from = self._abspath(rel_from)
 
442
        abs_to = self._abspath(rel_to)
 
443
        mutter("FTP rename: %s => %s", abs_from, abs_to)
 
444
        f = self._get_FTP()
 
445
        return self._rename(abs_from, abs_to, f)
 
446
 
 
447
    def _rename(self, abs_from, abs_to, f):
 
448
        try:
 
449
            f.rename(abs_from, abs_to)
 
450
        except ftplib.error_perm, e:
 
451
            self._translate_perm_error(e, abs_from,
 
452
                ': unable to rename to %r' % (abs_to))
 
453
 
437
454
    def move(self, rel_from, rel_to):
438
455
        """Move the item at rel_from to the location at rel_to"""
439
456
        abs_from = self._abspath(rel_from)
441
458
        try:
442
459
            mutter("FTP mv: %s => %s", abs_from, abs_to)
443
460
            f = self._get_FTP()
444
 
            f.rename(abs_from, abs_to)
 
461
            self._rename_and_overwrite(abs_from, abs_to, f)
445
462
        except ftplib.error_perm, e:
446
463
            self._translate_perm_error(e, abs_from,
447
464
                extra='unable to rename to %r' % (rel_to,), 
448
465
                unknown_exc=errors.PathError)
449
466
 
450
 
    rename = move
 
467
    def _rename_and_overwrite(self, abs_from, abs_to, f):
 
468
        """Do a fancy rename on the remote server.
 
469
 
 
470
        Using the implementation provided by osutils.
 
471
        """
 
472
        osutils.fancy_rename(abs_from, abs_to,
 
473
            rename_func=lambda p1, p2: self._rename(p1, p2, f),
 
474
            unlink_func=lambda p: self._delete(p, f))
451
475
 
452
476
    def delete(self, relpath):
453
477
        """Delete the item at relpath"""
454
478
        abspath = self._abspath(relpath)
 
479
        f = self._get_FTP()
 
480
        self._delete(abspath, f)
 
481
 
 
482
    def _delete(self, abspath, f):
455
483
        try:
456
484
            mutter("FTP rm: %s", abspath)
457
 
            f = self._get_FTP()
458
485
            f.delete(abspath)
459
486
        except ftplib.error_perm, e:
460
487
            self._translate_perm_error(e, abspath, 'error deleting',
666
693
            pfrom = self.filesystem.translate(self._renaming)
667
694
            self._renaming = None
668
695
            pto = self.filesystem.translate(line[1])
 
696
            if os.path.exists(pto):
 
697
                self.respond('550 RNTO failed: file exists')
 
698
                return
669
699
            try:
670
700
                os.rename(pfrom, pto)
671
701
            except (IOError, OSError), e: