duplicity-team team mailing list archive
-
duplicity-team team
-
Mailing list archive
-
Message #01338
[MERGE] Corects remote path to have one single slash
Greetings,
I found that I was not able to interact with Godaddy's ftp-based storage
with duplicity. Looking further, found the the put() and get() methods
in ftpbackend were stripping all the starting slashes from the remote
path. This reflects a python api change, where the call is now lstrip(s,
n). I did not change the call, because in my experience, expecting the
right number of slashes is unreliable. Rather, I added '/' to the
sprintf formatting strings.
Yours,
Jed Reynolds
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: jed@xxxxxxxxxxxxxx-20121003141903-5m3jc8lkkb68qxy1
# target_branch: bzr+ssh://bazaar.launchpad.net/+branch/duplicity/
# testament_sha1: c13abf28d343e9b1f471d16b7cb7f9e561d448af
# timestamp: 2012-10-03 07:22:48 -0700
# base_revision_id: michael.terry@xxxxxxxxxxxxx-20121002221843-\
# ql9em3gu3ug0uk6b
#
# Begin patch
=== modified file 'duplicity/backends/ftpbackend.py'
--- duplicity/backends/ftpbackend.py 2011-06-17 06:21:42 +0000
+++ duplicity/backends/ftpbackend.py 2012-10-03 14:19:03 +0000
@@ -29,96 +29,96 @@
from duplicity import tempdir
class FTPBackend(duplicity.backend.Backend):
- """Connect to remote store using File Transfer Protocol"""
- def __init__(self, parsed_url):
- duplicity.backend.Backend.__init__(self, parsed_url)
-
- # we expect an error return, so go low-level and ignore it
- try:
- p = os.popen("ncftpls -v")
- fout = p.read()
- ret = p.close()
- except Exception:
- pass
- # the expected error is 8 in the high-byte and some output
- if ret != 0x0800 or not fout:
- log.FatalError("NcFTP not found: Please install NcFTP version 3.1.9 or later",
- log.ErrorCode.ftp_ncftp_missing)
-
- # version is the second word of the first line
- version = fout.split('\n')[0].split()[1]
- if version < "3.1.9":
- log.FatalError("NcFTP too old: Duplicity requires NcFTP version 3.1.9,"
- "3.2.1 or later. Version 3.2.0 will not work properly.",
- log.ErrorCode.ftp_ncftp_too_old)
- elif version == "3.2.0":
- log.Warn("NcFTP (ncftpput) version 3.2.0 may fail with duplicity.\n"
- "see: http://www.ncftpd.com/ncftp/doc/changelog.html\n"
- "If you have trouble, please upgrade to 3.2.1 or later",
- log.WarningCode.ftp_ncftp_v320)
- log.Notice("NcFTP version is %s" % version)
-
- self.parsed_url = parsed_url
-
- self.url_string = duplicity.backend.strip_auth_from_url(self.parsed_url)
-
- # This squelches the "file not found" result from ncftpls when
- # the ftp backend looks for a collection that does not exist.
- # version 3.2.2 has error code 5, 1280 is some legacy value
- self.popen_persist_breaks[ 'ncftpls' ] = [ 5, 1280 ]
-
- # Use an explicit directory name.
- if self.url_string[-1] != '/':
- self.url_string += '/'
-
- self.password = self.get_password()
-
- if globals.ftp_connection == 'regular':
- self.conn_opt = '-E'
- else:
- self.conn_opt = '-F'
-
- self.tempfile, self.tempname = tempdir.default().mkstemp()
- os.write(self.tempfile, "host %s\n" % self.parsed_url.hostname)
- os.write(self.tempfile, "user %s\n" % self.parsed_url.username)
- os.write(self.tempfile, "pass %s\n" % self.password)
- os.close(self.tempfile)
- self.flags = "-f %s %s -t %s -o useCLNT=0,useHELP_SITE=0 " % \
- (self.tempname, self.conn_opt, globals.timeout)
- if parsed_url.port != None and parsed_url.port != 21:
- self.flags += " -P '%s'" % (parsed_url.port)
-
- def put(self, source_path, remote_filename = None):
- """Transfer source_path to remote_filename"""
- if not remote_filename:
- remote_filename = source_path.get_filename()
- remote_path = os.path.join(urllib.unquote(self.parsed_url.path.lstrip('/')), remote_filename).rstrip()
- commandline = "ncftpput %s -m -V -C '%s' '%s'" % \
- (self.flags, source_path.name, remote_path)
- self.run_command_persist(commandline)
-
- def get(self, remote_filename, local_path):
- """Get remote filename, saving it to local_path"""
- remote_path = os.path.join(urllib.unquote(self.parsed_url.path), remote_filename).rstrip()
- commandline = "ncftpget %s -V -C '%s' '%s' '%s'" % \
- (self.flags, self.parsed_url.hostname, remote_path.lstrip('/'), local_path.name)
- self.run_command_persist(commandline)
- local_path.setdata()
-
- def list(self):
- """List files in directory"""
- # Do a long listing to avoid connection reset
- commandline = "ncftpls %s -l '%s'" % (self.flags, self.url_string)
- l = self.popen_persist(commandline).split('\n')
- l = filter(lambda x: x, l)
- # Look for our files as the last element of a long list line
- return [x.split()[-1] for x in l if not x.startswith("total ")]
-
- def delete(self, filename_list):
- """Delete files in filename_list"""
- for filename in filename_list:
- commandline = "ncftpls %s -l -X 'DELE %s' '%s'" % \
- (self.flags, filename, self.url_string)
- self.popen_persist(commandline)
+ """Connect to remote store using File Transfer Protocol"""
+ def __init__(self, parsed_url):
+ duplicity.backend.Backend.__init__(self, parsed_url)
+
+ # we expect an error return, so go low-level and ignore it
+ try:
+ p = os.popen("ncftpls -v")
+ fout = p.read()
+ ret = p.close()
+ except Exception:
+ pass
+ # the expected error is 8 in the high-byte and some output
+ if ret != 0x0800 or not fout:
+ log.FatalError("NcFTP not found: Please install NcFTP version 3.1.9 or later",
+ log.ErrorCode.ftp_ncftp_missing)
+
+ # version is the second word of the first line
+ version = fout.split('\n')[0].split()[1]
+ if version < "3.1.9":
+ log.FatalError("NcFTP too old: Duplicity requires NcFTP version 3.1.9,"
+ "3.2.1 or later. Version 3.2.0 will not work properly.",
+ log.ErrorCode.ftp_ncftp_too_old)
+ elif version == "3.2.0":
+ log.Warn("NcFTP (ncftpput) version 3.2.0 may fail with duplicity.\n"
+ "see: http://www.ncftpd.com/ncftp/doc/changelog.html\n"
+ "If you have trouble, please upgrade to 3.2.1 or later",
+ log.WarningCode.ftp_ncftp_v320)
+ log.Notice("NcFTP version is %s" % version)
+
+ self.parsed_url = parsed_url
+
+ self.url_string = duplicity.backend.strip_auth_from_url(self.parsed_url)
+
+ # This squelches the "file not found" result from ncftpls when
+ # the ftp backend looks for a collection that does not exist.
+ # version 3.2.2 has error code 5, 1280 is some legacy value
+ self.popen_persist_breaks[ 'ncftpls' ] = [ 5, 1280 ]
+
+ # Use an explicit directory name.
+ if self.url_string[-1] != '/':
+ self.url_string += '/'
+
+ self.password = self.get_password()
+
+ if globals.ftp_connection == 'regular':
+ self.conn_opt = '-E'
+ else:
+ self.conn_opt = '-F'
+
+ self.tempfile, self.tempname = tempdir.default().mkstemp()
+ os.write(self.tempfile, "host %s\n" % self.parsed_url.hostname)
+ os.write(self.tempfile, "user %s\n" % self.parsed_url.username)
+ os.write(self.tempfile, "pass %s\n" % self.password)
+ os.close(self.tempfile)
+ self.flags = "-f %s %s -t %s -o useCLNT=0,useHELP_SITE=0 " % \
+ (self.tempname, self.conn_opt, globals.timeout)
+ if parsed_url.port != None and parsed_url.port != 21:
+ self.flags += " -P '%s'" % (parsed_url.port)
+
+ def put(self, source_path, remote_filename = None):
+ """Transfer source_path to remote_filename"""
+ if not remote_filename:
+ remote_filename = source_path.get_filename()
+ remote_path = os.path.join(urllib.unquote(self.parsed_url.path), remote_filename).rstrip()
+ commandline = "ncftpput %s -m -V -C '%s' '/%s'" % \
+ (self.flags, source_path.name, remote_path.lstrip('/'))
+ self.run_command_persist(commandline)
+
+ def get(self, remote_filename, local_path):
+ """Get remote filename, saving it to local_path"""
+ remote_path = os.path.join(urllib.unquote(self.parsed_url.path), remote_filename).rstrip()
+ commandline = "ncftpget %s -V -C '%s' '/%s' '%s'" % \
+ (self.flags, self.parsed_url.hostname, remote_path.lstrip('/'), local_path.name)
+ self.run_command_persist(commandline)
+ local_path.setdata()
+
+ def list(self):
+ """List files in directory"""
+ # Do a long listing to avoid connection reset
+ commandline = "ncftpls %s -l '%s'" % (self.flags, self.url_string)
+ l = self.popen_persist(commandline).split('\n')
+ l = filter(lambda x: x, l)
+ # Look for our files as the last element of a long list line
+ return [x.split()[-1] for x in l if not x.startswith("total ")]
+
+ def delete(self, filename_list):
+ """Delete files in filename_list"""
+ for filename in filename_list:
+ commandline = "ncftpls %s -l -X 'DELE %s' '%s'" % \
+ (self.flags, filename, self.url_string)
+ self.popen_persist(commandline)
duplicity.backend.register_backend("ftp", FTPBackend)
# Begin bundle
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
HBPPT26dpYo/8XckU4UJDCVqQ4A=
Follow ups