继续接上篇。
理论上来说,rsync是最好的工程同步方式。只是和fabric自身的ssh登录没有整合,现在我找到了一个简单的解决方法。同时我也准备了其他两种方法:打包上传和远程svn update,这样加上不同步总共有四个部署策略。
解决rsync依赖主机名和密码的方法很简单:因为rsync是在本地运行,只要在rsync之前执行一个简单的远程命令就能获得主机名和密码。代码如下:
remote_srcdir = 'source' run('hostname') # simple workaround for host prompt local('sshpass -p %s rsync -pthrvz --delete --exclude=.git --exclude=*fabfile* --exclude=target . %s:%s' % (env.password, env.host_string, remote_srcdir))
这里写死是密码登录了,理论还有证书登录,暂时不考虑。
打包上传的方式,改造自upload_project
import tempfile, os remote_srcdir = 'source' _, archive_path = tempfile.mkstemp() _, archive_name = os.path.split(archive_path) try: local('tar -cz --exclude-vcs --exclude=*fabfile* --exclude=target -f %s .' % archive_path) put(archive_path, '.') run('rm -rf %s' % remote_srcdir) run('mkdir %s' % remote_srcdir) run('tar -xzf %s -C %s' % (archive_name, remote_srcdir)) run('rm -f %s' % archive_name) finally: local('rm -f %s' % archive_path)
使用临时文件。本地打包,上传到远程服务器。远程服务器上解压缩后删除,最后删除本地临时文件。
远程svn update方式
import subprocess remote_srcdir = 'source' if _test_svn_info(remote_srcdir): run('svn update %s' % remote_srcdir) else: run('rm -rf %s' % remote_srcdir) git_svn_url = _call_shell("git svn info | fgrep URL | cut -d ' ' -f 2") svn_url = _call_shell("svn info | fgrep URL | cut -d ' ' -f 2") run('svn checkout %s %s' % ((git_svn_url or svn_url).strip(), remote_srcdir)) def _test_svn_info(srcdir): with settings(warn_only = True): return run('svn info %s' % srcdir).return_code == 0 def _call_shell(cmd): p = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) out, err = p.communicate() # ignore error return out
考虑到本地可能是git-svn而不是纯的svn,所以先判断远程代码代码是否是svn目录,如果不是则尝试从本地读取URL并在远程服务器上签出。如果是则直接执行svn update。
至此,个人认为工程同步这块算是基本完美了。若有更好的同步方法,欢迎指出。