[PATCH] knit pushing with ftp transport
Alexandre Saint
stalst at gmail.com
Mon May 1 11:46:36 BST 2006
On Sun, Apr 30, 2006 at 03:34:02PM -0500, John Arbash Meinel wrote:
> Alexandre Saint wrote:
> > Hello,
> >
> > This patch adds support for knit format to the ftp transport.
> >
> > Added an append() method using FTP 'APPE' command.
> > Modified copy() to deal well with relative paths (and not only with
> > absolute ones).
> >
> > Regards.
> >
> >
>
> I just realized something while looking over this code. Did we ever
> specify that the File-like object needs to be seekable? And that we must
> be able to backtrack? (One example is you cannot seek stdin).
>
> Since the line where you copy the bytes is just doing:
> conn.sendall(f.read())
> I'm wondering if it wouldn't be better to change things, and have the
> helper function (which gets retries), take a string buffer, rather than
> seeking on the file object.
>
Changed made according to your suggestion.
Though, is 'isinstance(text, str)' the good way to check if we are given
a str object or not?
> Other than that, +1 from me.
>
> John
> =:->
>
>
--
alex
-------------- next part --------------
=== modified file 'a/bzrlib/transport/ftp.py'
--- a/bzrlib/transport/ftp.py
+++ b/bzrlib/transport/ftp.py
@@ -303,11 +303,55 @@
raise TransportError(msg="Cannot remove directory at %s" % \
self._abspath(rel_path), extra=str(e))
- def append(self, relpath, f):
+ def append(self, relpath, f, mode=None, retries=0):
"""Append the text in the file-like object into the final
location.
"""
- raise TransportNotPossible('ftp does not support append()')
+ if not isinstance(f, str):
+ f = f.read()
+ try:
+ abspath = self._abspath(relpath)
+ mutter("FTP appe to %s" % abspath)
+ ftp = self._get_FTP()
+ if self.has(relpath):
+ result = ftp.size(abspath)
+ else:
+ result = 0
+ ftp.voidcmd("TYPE I")
+ cmd = "APPE %s" % abspath
+ conn = ftp.transfercmd(cmd)
+ conn.sendall(f)
+ conn.close()
+ if mode is not None:
+ self._setmode(relpath, mode)
+ ftp.getresp()
+ return result
+ except ftplib.error_perm, e:
+ FtpTransportError("Error appending data to %s" % abspath,
+ orig_error=e)
+ except ftplib.error_temp, e:
+ if retries > _number_of_retries:
+ raise TransportError("FTP temporary error during APPEND %s." \
+ "Aborting." % self.abspath(relpath), orig_error=e)
+ else:
+ warning("FTP temporary error: %s. Retrying." % str(e))
+ self._FTP_instance = None
+ self.append(relpath, f, retries=retries+1)
+
+ def _setmode(self, relpath, mode):
+ """Set permissions on a path.
+
+ Only set permissions if the FTP server support the 'SITE CHMOD'
+ extension.
+ """
+ try:
+ ftp = self._get_FTP()
+ cmd = "SITE CHMOD %s %s" % (self._abspath(relpath), str(mode))
+ ftp.sendcmd(cmd)
+ except ftplib.error_perm, e:
+ # Command probably not available on this server
+ pass
+
def copy(self, rel_from, rel_to):
"""Copy the item at rel_from to the location at rel_to"""
@@ -347,11 +391,12 @@
mutter("FTP nlst: %s" % self._abspath(relpath))
f = self._get_FTP()
basepath = self._abspath(relpath)
- # FTP.nlst returns paths prefixed by relpath, strip 'em
- the_list = f.nlst(basepath)
- stripped = [path[len(basepath)+1:] for path in the_list]
+ paths = f.nlst(basepath)
+ # If FTP.nlst returns paths prefixed by relpath, strip 'em
+ if paths[0].startswith(basepath):
+ paths = [path[len(basepath)+1:] for path in paths]
# Remove . and .. if present, and return
- return [path for path in stripped if path not in (".", "..")]
+ return [path for path in paths if path not in (".", "..")]
except ftplib.error_perm, e:
raise TransportError(orig_error=e)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 191 bytes
Desc: not available
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20060501/672bf030/attachment.pgp
More information about the bazaar
mailing list