~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/ftp.py

  • Committer: John Arbash Meinel
  • Date: 2007-01-31 17:48:55 UTC
  • mto: This revision was merged to the branch mainline in revision 2249.
  • Revision ID: john@arbash-meinel.com-20070131174855-gxkjd9rvy17uc6ko
Switch from for line in foo: f.write(line) to f.writelines(foo)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005 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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
37
37
import random
38
38
from warnings import warn
39
39
 
 
40
from bzrlib import (
 
41
    errors,
 
42
    urlutils,
 
43
    )
 
44
from bzrlib.trace import mutter, warning
40
45
from bzrlib.transport import (
41
 
    Transport,
42
46
    Server,
43
47
    split_url,
 
48
    Transport,
44
49
    )
45
 
import bzrlib.errors as errors
46
 
from bzrlib.trace import mutter, warning
47
50
import bzrlib.ui
48
51
 
49
52
_have_medusa = False
122
125
            netloc = '%s@%s' % (urllib.quote(self._username), netloc)
123
126
        if self._port is not None:
124
127
            netloc = '%s:%d' % (netloc, self._port)
125
 
        return urlparse.urlunparse(('ftp', netloc, path, '', '', ''))
 
128
        proto = 'ftp'
 
129
        if self.is_active:
 
130
            proto = 'aftp'
 
131
        return urlparse.urlunparse((proto, netloc, path, '', '', ''))
126
132
 
127
133
    def _get_FTP(self):
128
134
        """Return the ftplib.FTP instance for this object."""
189
195
 
190
196
    def _abspath(self, relpath):
191
197
        assert isinstance(relpath, basestring)
192
 
        relpath = urllib.unquote(relpath)
193
 
        relpath_parts = relpath.split('/')
194
 
        if len(relpath_parts) > 1:
195
 
            if relpath_parts[0] == '':
196
 
                raise ValueError("path %r within branch %r seems to be absolute"
197
 
                                 % (relpath, self._path))
198
 
        basepath = self._path.split('/')
 
198
        relpath = urlutils.unescape(relpath)
 
199
        if relpath.startswith('/'):
 
200
            basepath = []
 
201
        else:
 
202
            basepath = self._path.split('/')
199
203
        if len(basepath) > 0 and basepath[-1] == '':
200
204
            basepath = basepath[:-1]
201
 
        for p in relpath_parts:
 
205
        for p in relpath.split('/'):
202
206
            if p == '..':
203
207
                if len(basepath) == 0:
204
208
                    # In most filesystems, a request for the parent
212
216
        # Possibly, we could use urlparse.urljoin() here, but
213
217
        # I'm concerned about when it chooses to strip the last
214
218
        # portion of the path, and when it doesn't.
215
 
        return '/'.join(basepath) or '/'
 
219
 
 
220
        # XXX: It seems that ftplib does not handle Unicode paths
 
221
        # at the same time, medusa won't handle utf8 paths
 
222
        # So if we .encode(utf8) here, then we get a Server failure.
 
223
        # while if we use str(), we get a UnicodeError, and the test suite
 
224
        # just skips testing UnicodePaths.
 
225
        return str('/'.join(basepath) or '/')
216
226
    
217
227
    def abspath(self, relpath):
218
228
        """Return the full url to the given relative path.
282
292
                self._FTP_instance = None
283
293
                return self.get(relpath, decode, retries+1)
284
294
 
285
 
    def put(self, relpath, fp, mode=None, retries=0):
 
295
    def put_file(self, relpath, fp, mode=None, retries=0):
286
296
        """Copy the file-like or string object into the location.
287
297
 
288
298
        :param relpath: Location to put the contents, relative to base.
295
305
        abspath = self._abspath(relpath)
296
306
        tmp_abspath = '%s.tmp.%.9f.%d.%d' % (abspath, time.time(),
297
307
                        os.getpid(), random.randint(0,0x7FFFFFFF))
298
 
        if not hasattr(fp, 'read'):
 
308
        if getattr(fp, 'read', None) is None:
299
309
            fp = StringIO(fp)
300
310
        try:
301
311
            mutter("FTP put: %s", abspath)
321
331
            else:
322
332
                warning("FTP temporary error: %s. Retrying.", str(e))
323
333
                self._FTP_instance = None
324
 
                self.put(relpath, fp, mode, retries+1)
 
334
                self.put_file(relpath, fp, mode, retries+1)
325
335
        except EOFError:
326
336
            if retries > _number_of_retries:
327
337
                raise errors.TransportError("FTP control connection closed during PUT %s."
330
340
                warning("FTP control connection closed. Trying to reopen.")
331
341
                time.sleep(_sleep_between_retries)
332
342
                self._FTP_instance = None
333
 
                self.put(relpath, fp, mode, retries+1)
 
343
                self.put_file(relpath, fp, mode, retries+1)
334
344
 
335
345
    def mkdir(self, relpath, mode=None):
336
346
        """Create a directory at the given path."""
353
363
        except ftplib.error_perm, e:
354
364
            self._translate_perm_error(e, abspath, unknown_exc=errors.PathError)
355
365
 
356
 
    def append(self, relpath, f, mode=None):
 
366
    def append_file(self, relpath, f, mode=None):
357
367
        """Append the text in the file-like object into the final
358
368
        location.
359
369
        """
453
463
 
454
464
    def list_dir(self, relpath):
455
465
        """See Transport.list_dir."""
 
466
        basepath = self._abspath(relpath)
 
467
        mutter("FTP nlst: %s", basepath)
 
468
        f = self._get_FTP()
456
469
        try:
457
 
            mutter("FTP nlst: %s", self._abspath(relpath))
458
 
            f = self._get_FTP()
459
 
            basepath = self._abspath(relpath)
460
470
            paths = f.nlst(basepath)
461
 
            # If FTP.nlst returns paths prefixed by relpath, strip 'em
462
 
            if paths and paths[0].startswith(basepath):
463
 
                paths = [path[len(basepath)+1:] for path in paths]
464
 
            # Remove . and .. if present, and return
465
 
            return [path for path in paths if path not in (".", "..")]
466
471
        except ftplib.error_perm, e:
467
472
            self._translate_perm_error(e, relpath, extra='error with list_dir')
 
473
        # If FTP.nlst returns paths prefixed by relpath, strip 'em
 
474
        if paths and paths[0].startswith(basepath):
 
475
            entries = [path[len(basepath)+1:] for path in paths]
 
476
        else:
 
477
            entries = paths
 
478
        # Remove . and .. if present
 
479
        return [urlutils.escape(entry) for entry in entries
 
480
                if entry not in ('.', '..')]
468
481
 
469
482
    def iter_files_recursive(self):
470
483
        """See Transport.iter_files_recursive.
473
486
        mutter("FTP iter_files_recursive")
474
487
        queue = list(self.list_dir("."))
475
488
        while queue:
476
 
            relpath = urllib.quote(queue.pop(0))
 
489
            relpath = queue.pop(0)
477
490
            st = self.stat(relpath)
478
491
            if stat.S_ISDIR(st.st_mode):
479
492
                for i, basename in enumerate(self.list_dir(relpath)):
670
683
            *why* it cannot make a directory.
671
684
            """
672
685
            if len (line) != 2:
673
 
                self.command_not_understood (string.join (line))
 
686
                self.command_not_understood(''.join(line))
674
687
            else:
675
688
                path = line[1]
676
689
                try: