[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