Skip to content

Instantly share code, notes, and snippets.

@dnozay
Created July 24, 2014 23:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dnozay/37e8148ee748068afb91 to your computer and use it in GitHub Desktop.
Save dnozay/37e8148ee748068afb91 to your computer and use it in GitHub Desktop.
ftp copy files recursively
# ftp + recursive copy
# License: MIT - http://opensource.org/licenses/MIT
import ftplib
import os
import getpass
import ssl
class RecursiveCopyMixin(object):
def rput(self, sourcedir, remotedir):
oldpwd = os.getcwd()
oldrempwd = self.pwd()
try:
self.cwd(remotedir)
os.chdir(sourcedir)
for root, dirs, files in os.walk('.'):
remroot = remotedir + root[1:]
# change remote directory so we
# don't need to manipulate filenames
# when comparing sets.
self.cwd(remroot)
# get subset of directories that don't exist
# so we can create them; you could modify the
# dirs in place if you wanted os.walk to not
# recurse into them.
mkdirs = set(dirs) - set(self.nlst())
for dir in mkdirs:
full_dir = os.path.join(remroot, dir)
print '* mkdir', full_dir
self.mkd(full_dir)
# same story for files, if they are present we
# do not send them; could be more clever about
# timestamps or file size.
missingfiles = set(files) - set(self.nlst())
for fname in missingfiles:
full_fname = os.path.join(root, fname)
remfull_fname = os.path.join(remroot, fname)
try:
print '* sending', remfull_fname
self.storbinary(
'STOR ' + remfull_fname,
open(full_fname, 'rb'))
except IOError as err:
# check for broken symlinks, which we'll ignore.
if os.path.exists(full_fname):
raise err
else:
print '[broken symlink?]', err
pass
finally:
# restore current directory
os.chdir(oldpwd)
self.cwd(oldrempwd)
class FTP(ftplib.FTP, RecursiveCopyMixin):
pass
class FTP_TLS(ftplib.FTP_TLS, RecursiveCopyMixin):
pass
class FTP_SSL(FTP_TLS):
ssl_version = ssl.PROTOCOL_SSLv3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment