2 from ftplib import FTP, all_errors
3 from netrc import netrc, NetrcParseError
4 from cumulus.store import Store, type_patterns, NotFoundError
6 class FtpStore (Store):
7 def __init__ (self, url, **kw):
10 upw, hp = self.netloc.split ('@')
15 host, port = hp.split (':')
21 user, passwd = upw.split (':')
28 user, acct, passwd = n.authenticators (host)
31 except (IOError, NetrcParseError):
34 self.ftp.connect (host, port)
35 self.ftp.login (user, passwd)
36 self.prefix = self.path [1:] # skip *only* first '/'
37 self.ftp.cwd (self.prefix)
39 def _get_path (self, type, name):
40 # we are in right directory
43 def list (self, type):
45 files = self.ftp.nlst ()
46 return (f for f in files if type_patterns[type].match (f))
48 def get (self, type, name):
50 sock = self.ftp.transfercmd ('RETR %s' % self._get_path (type, name))
52 return sock.makefile ()
54 def put (self, type, name, fp):
56 self.ftp.storbinary ("STOR %s" % self._get_path (type, name), fp)
58 def delete (self, type, name):
60 self.ftp.delete (self._get_path (type, name))
62 def stat (self, type, name):
63 """ Note that the size-command is non-standard but supported by
64 most ftp servers today. If size returns an error condition we
65 try nlst to detect if the file exists and return an bogus length
68 fn = self._get_path (type, name)
71 # my client doesn't accept size in ascii-mode
72 self.ftp.sendcmd ('TYPE I')
73 size = self.ftp.size (fn)
74 self.ftp.sendcmd ('TYPE A')
75 except all_errors, err:
80 print "nlst: %s" % fn, size
81 l = self.ftp.nlst (fn)
84 raise NotFoundError, (type, name)
87 """ After a get command at end of transfer a 2XX reply is still
88 in the input-queue, we have to get rid of that