Subversionで、あるリビジョン以降の差分をいきなりFTP
昨日の
Subversionで、あるリビジョン以降の差分をファイルで抽出 - なんたらノート 第二期
をもとに、エクスポートファイルを吐出さず、直接FTPするツールを作りました。
本当なら、ファイルとしてエクスポートして、きっちり確認しながらアップロードするべきだけど、もう「最後3リビジョンの変更だけ、さっさとFTPしたいんよ」というような場合もありますね。
#!/usr/bin/env python #!coding: utf-8 import sys, os, re, getpass from optparse import OptionParser from ftplib import FTP def list_changed_path(ws, rev): if not re.search(":", rev): rev += ":HEAD" pwd = os.getcwd() try: os.chdir(ws) svnfd = os.popen('svn diff -r%s --summarize .' % rev, 'r') overwrite = [] remove = [] for line in svnfd: mo = re.match(r'^\s*([AMD])\s*(.*)$', line.strip()) if mo: print line.strip() if mo.group(1) in ['A', 'M']: overwrite.append(mo.group(2).strip(" \n")) elif mo.group(1) in ['D']: remove.append(mo.group(2).strip(" \n")) svnfd.close() finally: os.chdir(pwd) overwrite.sort() remove.sort() return (overwrite, remove) if __name__ == '__main__': parser = OptionParser( usage="%prog [options] <workspace> <rev>[:<rev>]", conflict_handler="resolve") parser.add_option("-f", "--force", dest="force", action="store_true", default=False, help="force executuion", metavar="PATH") parser.add_option("-h", "--host", dest="host", help="target host name", metavar="HOST") parser.add_option("-u", "--user", dest="user", help="user account name", metavar="USER") parser.add_option("-p", "--password", dest="password", help="password", metavar="PASSWORD") parser.add_option("-d", "--destpath", dest="destpath", help="destination path on FTP server", metavar="PATH") (options, args) = parser.parse_args() if(len(args) != 2): parser.error("Must be specified both of workspace and rev!") ws,rev = args def checked_input(prompt, test=lambda i: i != "", echo=True): i = raw_input(prompt) if echo else getpass.getpass(prompt) pad = " " * len(prompt) while not test(i): i = raw_input(pad) if echo else getpass.getpass(pad) return i # parse svn diff summary overwrite, remove = list_changed_path(ws, rev) # confirm if options.force: do_ftp = True else: do_ftp = dict(y=True, n=False).get(checked_input("Upload these files? (y/n) ", test=lambda i: i[0].lower() in ('y', 'n'))[0]) if not do_ftp: sys.exit() # connect ftp host = options.host or checked_input("host:") user = options.user or checked_input("user:") password = options.password or checked_input("password:", test=lambda x: True, echo=False) destpath = options.destpath or checked_input("destination path:") ftp = FTP(host, user, password) ftp.cwd(destpath) # upload ASCII_TYPES = ( 'html', 'htm', 'xhtml', 'xhtm', 'css', 'js', 'txt', 'csv', 'xml', 'json', 'yml', 'yaml', 'cgi', 'pl', 'php', 'inc', 'phtml', 'tpl', 'py', 'rb' ) for p in overwrite: s = "/".join([ws, p]) d = "/".join([destpath, p.replace("\\", "/")]) if os.path.isfile(s): ext = s[s.rfind(".")+1:] try: if ext in ASCII_TYPES: sf = file(s, 'rt') ftp.storlines("STOR %s" % d, sf) sf.close() print "copy(a) %s" % d else: sf = file(s, 'rb') ftp.storbinary("STOR %s" % d, sf) sf.close() print "copy(b) %s" % d except: print "!copy %s ==> failed" % d elif os.path.isdir(s): try: ftp.mkd(d) print "mkdir %s" % d except: print "!mkdir %s ==> failed" % d # remove for p in reversed(remove): d = "/".join([destpath, p.replace("\\", "/")]) try: ftp.delete(d) print "rm %s" % d except: print "!rm %s ==> failed" % d ftp.quit();
使い方は
svn-ftp-changes --help
で確認してください。
FTPでの同期そのものはあまりがんばって作ってないので、ちょくちょく、ディレクトリが作れなかったりして失敗します。失敗した処理は手作業で。
そもそも、数コミット分まで程度の、ごく小さな変更を即座にアップロードすることしか想定してないので、リビジョン1からごっそり全自動FTPというのは、避けたほうが安全です。