[fabric]多种策略的工程同步


继续接上篇

理论上来说,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。

至此,个人认为工程同步这块算是基本完美了。若有更好的同步方法,欢迎指出。