FTP 自動アップローダー
【追記】 Bitbucket にリポジトリとしておきました。 いい感じに手直ししていただけると嬉しいです。 yosida95 / AutoFTPUploader / overview — Bitbucket
任意のディレクトリを監視し、ディレクトリの中にあるファイルと FTP で接続したサーバーとを同期するものを作ってみました。 俺得です。 とりあえず同期出来ればいいや、てきな考えなので完成度はべらぼうに低いです。
ローカルディレクトリ内のファイルが上書きされればサーバー上のファイルも上書きし、ローカルディレクトリ内にファイルが追加されればそれをサーバーにアップロードし、ローカルディレクトリ内のファイルが削除されればサーバー上のファイルも削除します。
なお、ディレクトリのネストには対応していませんので、子ディレクトリも監視するときは、別プロセスで対応してください。
#!/usr/bin/env python
#-*-coding: utf-8-*-
import signal
import time
import sys
import os
from ftplib import FTP, error_temp
class Upload:
def __init__(self):
self.server = raw_input(u'FTP Server: ')
self.port = raw_input(u'Port: ')
self.user = raw_input(u'User: ')
self.passwd = raw_input(u'Password: ')
self.pasv = raw_input(u'PASV?(yes/no): ')
self.pasv = True if self.pasv == 'yes' else False
self.remote_path = raw_input(u'Remote Path: ')
self.ascii_exts = [
'.txt',
'.log',
'.htm',
'.html',
'.xhtml',
'.css',
'.js',
'.cgi',
'.py',
'.pl',
'.php'
]
self._queue = {'new': [], 'update': [], 'deleted': []}
self.__connect()
def __connect(self):
self.ftp = FTP()
self.ftp.set_debuglevel(0)
try:
self.ftp.connect(self.server, self.port)
self.ftp.login(self.user, self.passwd)
self.ftp.set_pasv(self.pasv)
self.ftp.cwd(self.remote_path)
print u'Connected'
except:
print u'Failed to connect'
exit(1)
def _run(self):
for x in self._queue['new']:
file = os.path.join(sys.argv[1], x)
try:
self._files[x] = {
'name': file,
'mtime': os.path.getmtime(file)
}
self.__upload(x)
except:
continue
for x in self._queue['update']:
file = os.path.join(sys.argv[1], x)
try:
self._files[x]['mtime'] = os.path.getmtime(file)
self.__upload(x)
except:
continue
for x in self._queue['deleted']:
self.__delete(x)
del self._files[x]
self._queue = {'new': [], 'update': [], 'deleted': []}
return True
def __upload(self, file):
(root, ext) = os.path.splitext(file)
try:
fr = open(self._files[file]['name'], 'r')
try:
if ext in self.ascii_exts:
self.ftp.storlines('STOR %s' % file, fr)
else:
self.ftp.storbinary('STOR %s' % file, fr)
except error_temp:
self.__connect()
if ext in self.ascii_exts:
self.ftp.storlines('STOR %s' % file, fr)
else:
self.ftp.storbinary('STOR %s' % file, fr)
print u'Uploaded: %s' % file
return True
except:
print u'Failed to upload: %s' % file
return False
def __delete(self, file, retry=True):
try:
try:
self.ftp.delete(file)
except error_temp:
self.__connect()
self.ftp.delete(file)
print 'Deleted: %s' % file
return True
except:
print 'Failed to delete: %s' % file
return False
class Monitoring(Upload):
def __init__(self):
Upload.__init__(self)
self._files = {}
self.__polling()
def __get_delta(self):
now = os.listdir(sys.argv[1])
before = self._files.keys()
for x in now:
if not x in before:
self._queue['new'].append(x)
for x in before:
if not x in now:
self._queue['deleted'].append(x)
def __polling(self):
while True:
self.__get_delta()
for x in self._files:
try:
if self._files[x]['mtime'] < os.path.getmtime(self._files[x]['name']):
self._queue['update'].append(x)
except:
continue
if not self._run():
print('Error!');
exit(1);
time.sleep(1)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal.SIG_DFL)
if len(sys.argv) == 2 and os.path.isdir(sys.argv[1]):
process = Monitoring()
else:
print "Please pass me filepath as argument."
また、接続する FTP サーバーがいつも一緒なのであれば、該当する raw_input を書き換えて静的に指定してやればいいと思います。
ascii_exts は ASCII 転送モードで転送するファイルの拡張子を詰めたリストです。 必要に応じて追加や削除をしてやってください。